Javascript

1年Vue项目经验总结(持续更新中...)

本文主要是介绍1年Vue项目经验总结(持续更新中...),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

前言

本文讲述了毕业实习和正式工作1年以来,使用Vue开发项目的一些个人经历和想法,仅是个人总结,如有不合理的地方,欢迎吐槽。以下是本文的大概内容。



1.Vue项目搭建

1.1从VueCli2到VueCli3

一开始实习接触Vue的脚手架是VueCli2版本,学习的webpack配置也都Cli2的,后来公司使用的是Cli3,所以有一个学习和适应的过程。
VueCli2和VueCli3的差别大概体现在:

  • 创建项目

3.0:vue create。
2.0:vue init webpack

  • 启动项目

3.0启动npm run serve
2.0启动npm run dev

  • 项目配置途径

2.0 config、build文件夹中进行项目的webpack、多环境和打包等配置
3.0 项目结构比2.0要简洁,缺少了build和confilg文件,可自行创建与package.json同级的 vue.config.js 文件,进行配置。
主要的常用配置整理如下:

// vue.config.js 基本配置方法
module.exports = {
  // 项目部署的基础路径
  // 我们默认假设你的应用将会部署在域名的根部,
  // 比如 https://www.my-app.com/
  // 如果你的应用时部署在一个子路径下,那么你需要在这里
  // 指定子路径。比如,如果你的应用部署在
  // https://www.foobar.com/my-app/
  // 那么将这个值改为 `/my-app/`
  // 基本路径 baseURL已经过时
  publicPath: './',
  
	// 打包项目时构建的文件目录,用法与webpack本身的output.path一致
  outputDir: 'dist', 
  
  // 静态资源目录 (js, css, img, fonts)
  assetsDir: 'assets',
  
  // eslint-loader 是否在保存的时候检查,编译不规范时,设为true在命令行中警告,若设为error则不仅警告,并且编译失败
  lintOnSave: true,
  
  // 调整内部的 webpack 配置。查阅 https://github.com/vuejs/vue-docs-zh-cn/blob/master/vue-cli/webpack.md
  chainWebpack: () => {},
  configureWebpack: () => {},
  
  // vue-loader 配置项 https://vue-loader.vuejs.org/en/options.html
   vueLoader: {},
  
  // 生产环境是否生成 sourceMap 文件,默认true,若不需要生产环境的sourceMap,可以设置为false,加速生产环境的构建
  productionSourceMap: true,
  
  // css相关配置
  css: {
   // 是否使用css分离插件 ExtractTextPlugin,采用独立样式文件载入,不采用<style>方式内联至html文件中
   extract: true,
   // 是否在构建样式地图,false将提高构建速度
   sourceMap: false,
   // css预设器配置项
   loaderOptions: {},
   // 启用 CSS modules for all css / pre-processor files.
   // 这个选项不会影响 `*.vue` 文件
   modules: false
  },
  
  // 在生产环境下为 Babel 和 TypeScript 使用 `thread-loader`
  // 在多核机器下会默认开启。
  parallel: require('os').cpus().length > 1,
  
  // 是否启用dll See https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#dll-mode
  dll: false,
  
  // PWA 插件相关配置 see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
  pwa: {},
  
  // webpack-dev-server 相关配置
  devServer: {
   open: process.platform === 'darwin',
   host: '0.0.0.0',//如果是真机测试,就使用这个IP
   port: 1234,
   https: false,
   hotOnly: false,
   proxy: null, // 设置代理
   // proxy: {
   //     '/api': {
   //         target: '<url>',
   //         ws: true,
   //         changOrigin: true
   //     }
   // },
   before: app => {}
  },
  // 第三方插件配置
  pluginOptions: {
   // ...
  }
 }
复制代码

1.2 Axios二次封装

axios二次封装的目的主要是三个方面:

  • 接口的请求拦截处理(配置处理、拦截重复请求)
  • 接口的响应拦截处理
  • API方法的封装复用

1.2.1 接口请求拦截处理

1.2.1.1 可配置项

在进行接口请求拦截进行配置处理的时候,针对以下参数,可以灵活配置。

参数 意义 例子
url 用于请求的服务器 URL url: '/user'
method 创建请求时使用的方法 method: 'get'
baseURL 自动加在 url 前面,除非 url 是一个绝对 URL,通过设置一个 baseURL 便于为 axios 实例的方法传递相对 URL baseURL: 'some-domain.com/api/'
transformRequest 允许在向服务器发送前,修改请求数据
 // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
 // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
   // 对 data 进行任意转换处理
return data;
 }],
headers 即将被发送的自定义请求头 headers: {'X-Requested-With': 'XMLHttpRequest'},
params 即将与请求一起发送的 URL 参数 params: {
   ID: 12345
},
paramsSerializer 负责 params 序列化的函数(e.g. www.npmjs.com/package/qs, api.jquery.com/jquery.para…) paramsSerializer: function(params) {
   return Qs.stringify(params, {arrayFormat: 'brackets'})
 }
data data 是作为请求主体被发送的数据
  只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  在没有设置 transformRequest 时,必须是以下类型之一:
- string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
- 浏览器专属:FormData, File, Blob
- Node 专属: Stream
data: {
   firstName: 'Fred'
 }
timeout 指定请求超时的毫秒数(0 表示无超时时间) timeout: 1000
adapter 允许自定义处理请求,以使测试更轻松,返回一个 promise 并应用一个有效的响应 adapter: function (config) {
   /* ... */
 },
auth 表示应该使用 HTTP 基础验证,并提供凭据,这将设置一个 Authorization 头,覆写掉现有的任意使用 headers 设置的自定义 Authorization auth: {
   username: 'janedoe',
   password: 's00pers3cret'
 },
responseType 服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream' responseType: 'json', // 默认的
xsrfCookieName 用作 xsrf token 的值的cookie的名称 xsrfCookieName: 'XSRF-TOKEN'
xsrfHeaderName 承载 xsrf token 的值的 HTTP 头的名称 xsrfHeaderName: 'X-XSRF-TOKEN', // 默认的
onUploadProgress 允许为上传处理进度事件 onUploadProgress: function (progressEvent) {
   // 对原生进度事件的处理
 },
onDownloadProgress 允许为下载处理进度事件 onDownloadProgress: function (progressEvent) {
   // 对原生进度事件的处理
 },
maxContentLength 定义允许的响应内容的最大尺寸 maxContentLength: 2000
validateStatus 定义对于给定的HTTP 响应状态码是 resolve 或 reject  promise 。如果 validateStatus 返回 true (或者设置为 nullundefined),promise 将被 resolve; 否则,promise 将被 rejecte validateStatus: function (status) {
   return status >= 200 && status < 300; // 默认的
 },
maxRedirects 定义在 node.js 中 follow 的最大重定向数目 maxRedirects: 5, // 默认的
httpAgent httpAgenthttpsAgent 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。 httpAgent: new http.Agent({ keepAlive: true }),
 httpsAgent: new https.Agent({ keepAlive: true }),
proxy 定义代理服务器的主机名称和端口 proxy: {
   host: '127.0.0.1',
   port: 9000,
   auth: : {
     username: 'mikeymike',
     password: 'rapunz3l'
   }
 },
cancelToken 指定用于取消请求的 cancel token cancelToken: new CancelToken(function (cancel) {
 })

1.2.1.2 拦截重复请求

在网速较慢的情况下,容易出现用户多次点击而重复请求使得页面抖动的问题,用户体验不好,因此进行拦截重复请求的处理。思路是:
创建请求队列 ---->

-----拦截处理------
标识即将发送的请求---->
判断即将发送的请求与队列中的请求是否相同---->
若相同则执行当前请求的取消方法,并从请求队列中删除---->
创建即将请求的取消方法,放入队列中

拦截处理

request.interceptors.request.use(
  config => {
    // 拦截重复请求(即当前正在进行的相同请求)
    const requestData = getRequestIdentify(config, true); // 标识请求
    removePending(requestData, true);// 取消重复请求
    config.cancelToken = new CancelToken((c) => { // 创建当前请求的取消方法
      pending[requestData] = c;
    });
    return config;
  }, error => {
  	return Promise.reject(error)
	})
复制代码


标识请求

const getRequestIdentify = (config, isReuest = false) => {
  let url = config.url;
  if (isReuest) {
    url = config.baseURL + config.url.substring(1, config.url.length);
  }
  return config.method === 'get' ? encodeURIComponent(url + JSON.stringify(config.params)) : encodeURIComponent(config.url + JSON.stringify(config.data));
};
复制代码


取消重复请求

const pending = {};
const CancelToken = axios.CancelToken;
const removePending = (key, isRequest = false) => {
  if (pending[key] && isRequest) {
    pending[key]('取消重复请求');
  }
  delete pending[key];
};
复制代码

1.2.2 接口响应拦截处理

接口响应的拦截主要是对接口返回的数据进行提取、封装使用,以及对请求异常进行统一配置处理。

request.interceptors.response.use(
  response => {
    const data = response.data || {};
    return data;
  },
  error => {
    const code = error.response.status;
    if (code) {
      let msg = '';
      switch (code) {
        case 400:
          msg = '请求错误';
          break;
        case 401:
          msg = '未授权,请登录';
          break;
        case 403:
          msg = '拒绝访问';
          break;
        case 404:
          msg = `请求${error.response.config.url}出现404错误`;
          break;
        case 408:
          msg = '请求超时';
          break;
        case 500:
          msg = '服务器内部错误';
          break;
        case 501:
          msg = '服务未实现';
          break;
        case 502:
          msg = '网关错误';
          break;
        case 503:
          msg = '服务不可用';
          break;
        case 504:
          msg = '网关超时';
          break;
        case 505:
          msg = 'HTTP版本不受支持';
          break;
      }
      Message.error(msg);
    }
    return Promise.reject(error);
  }
)
复制代码

1.2.3 API方法封装

单独封装接口请求方法, GET方法的参数为params,POST方法的参数为data。

// api.js
import request from '@/utils/request';

export function APIPostMethod(data) { // 自定义接口方法
  return request({
    url: '/url1',
    method: 'post',
    data
  });
}
export function APIGetMethod(params) { // 自定义接口方法
  return request({
    url: '/url2',
    method: 'get',
    params
  });
}
复制代码

在业务中调用API方法

import { APIGetMethod, APIPostMethod } from '@/utils/request';
const params = {}
APIGetMethod(params).then(res => {
//...
//对数据处理
})
复制代码

1.3跨域处理

简单来说,为了防止XSS和CSFR攻击,浏览器的同源策略限制带来了前后端分离开发时的跨域问题。即当请求与响应不在同一个协议+域名+端口下,就不会被浏览器允许。但是同源策略只是浏览器的一种策略,不是HTTP协议的一部分,因此服务端调用HTTP接口只是使用HTTP协议,而不会通过浏览器,更不会执行JS脚本,所以不会触发同源策略机制,不存在跨域问题。针对这个特点,可以从前端配置代理服务器入手。
尝试过两种解决跨域的方法:
1.Node.js中间件代理
在vue-cli中,里用node+webpack+webpack-dev-server代理接口跨域。

//vue.config.js
const config = {
  // ...
  devServer: {
    hot: true,
    open: true,
    host: '127.0.0.1',
    // host: '0.0.0.0',//如果是真机测试,就使用这个IP
    port: 8899,
    https: false,
    hotOnly: false,
    proxy: {
      '/': {
        target: 'http://xxx.xxx.xx.xx:xxxx/',
        logLevel: 'debug',
        ws: false,
        changOrigin: true
      }
    }
  }
}
module.exports = config;
复制代码

2.Nginx反向代理
通过nginx配置一个代理服务器,域名与本地域名A一致,但端口不同,反向代理访问对方B域名下的接口。

#proxy服务器
server {
        listen       8088;
        server_name  _;
        client_max_body_size 50m;

        location / {
            root   html/dist;
            try_files $uri $uri/ /index.html;
            index  /index.html;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
        }
        location ^~/api {
            proxy_pass	http://xxx.xxx.xx.xx:xxxx/api;
            proxy_redirect default;
        }
}
复制代码


前端在启动项目的时候,需要把项目proxy代理对应的8088端口上(感觉这种方式有点多余,但是同事用这种方式,咱不敢说,所以个人这边是用的第一种)。

Nginx的方式更适合用于线上部署解决跨域使用,开发环境下,使用vue-cli中的devserve既方便又快捷。


2.Vue技巧

2.1 懒加载

懒加载也叫延迟加载,使组件进行异步加载。目的是延迟非必要资源的加载,减少页面加载的时间,从而优化页面的性能。

2.1.1 路由懒加载

export default new Router({
  routes:[
    {
     path: '/test',
     name: 'test',
      //懒加载
     component: resolve => require(['../page/test.vue'], resolve),
    },
  ]
})
复制代码

在路由懒加载下,代码根据路由被拆分为不同的代码块,在切换进入相应的路由时,才对对应的代码块进行加载,加载更加高效了。

image.png

2.1.2 组件懒加载

components: {
  UpdateModal: resolve => { require(['./UpdateNormalTaskModal'], resolve); }
},
复制代码

在路由懒加载的前提下,进行组件懒加载的对比实验。
未使用组件懒加载:

image.png

整个页面为一个js,大小为718KB,加载耗时166ms。
在使用组件懒加载的时候:
image.png

整个页面被拆分为三个js(53.js),其中懒加载的两个组件,各自一个js(78.js、91.js),可看出来,53.js的文件大小变小,加载速度变快,将一个js拆分为多个进行并行加载,可以提高加载的效率,从而提升性能。

2.2按需引入

按需加载一般用于在使用第三方库的时候,为了避免第三方库过大,而造成的对首屏加载带来的过大的压力。
以VantUI按需加载为例

  • 安装babel-plugin-import
    npm i babel-plugin-import -D
  • 在babel.config.js中配置plugins(插件)
module.exports = {
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ],
  presets: [
    '@vue/app'
  ]
};
复制代码
  • 在要用到三方组件的vue文件中引入使用
import { Swipe, SwipeItem, ImagePreview } from 'vant';
export default {
  components: {
    vanSwipe: Swipe,
    vanSwipeItem: SwipeItem,
  }
}
复制代码

2.3 JS中使用本地图片资源

在vue的v-bind语法中使用到本地资源时,路径是相对本地文件夹的相对路径,打包时无法解析。

2.3.1.静态资源读取

将图片资源放在static静态资源文件夹下,在使用src时,直接访问根目录下的资源
比如图片放在public目录下,路径直接写为'/img/case/gkjg/7.jpg'

image.png

2.3.2导入资源

在data中采用require的方式,将图片资源导入,然后使用imgUrl变量。

data(){
  return {
		imgUrl:require("../assets/test.png")
  }
}
复制代码

2.4 keep-alive

<keep-alive></keep-alive>包含的组件会被缓存下来,不进行再次渲染DOM,从而节省性能,切换内容时会出发activated和deactivated两个生命周期钩子函数,被缓存的组件会保留当前组件的状态。

2.4.1路由页面缓存

利用router的meta字段

//...router.js
export default new Router({
  routes: [
    {
      path: '/',
      name: 'Hello',
      component: Hello,
      meta: {
        keepAlive: false // 不需要缓存
      }
    },
    {
      path: '/page1',
      name: 'Page1',
      component: Page1,
      meta: {
        keepAlive: true // 需要被缓存
      }
    }
  ]
})
复制代码
 <keep-alive> 
    <router-view v-if="$route.meta.keepAlive"></router-view> 
 </keep-alive> 
 <router-view v-if="!$route.meta.keepAlive"></router-view> 
复制代码

2.4.2组件缓存

<keep-alive include="test-keep-alive">
  <!-- 将缓存name为test-keep-alive的组件 -->
  <component></component>
</keep-alive>

<keep-alive include="a,b">
  <!-- 将缓存name为a或者b的组件,结合动态组件使用 -->
  <component :is="view"></component>
</keep-alive>

<!-- 使用正则表达式,需使用v-bind -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>

<keep-alive exclude="test-keep-alive">
  <!-- 将不缓存name为test-keep-alive的组件 -->
  <component></component>
</keep-alive>

复制代码

2.4.3 结合berforeRouteEnter

结合路由beforeRouteLeave(to, from, next)的钩子,设置to.meta.keepAlive 来指定目的页面是否进行keepAlive。

export default {
    data() {
        return {};
    },
    methods: {},
    beforeRouteLeave(to, from, next) {
         // 设置下一个路由的 meta
        to.meta.keepAlive = true;  // 当前页面跳转到下一个页面时,让目的页面缓存,不刷新
        next();
    }
};
复制代码


恰当使用keep-alive,结合activated和deactivated两个钩子函数,将不需要更新的内容缓存下来,将需要更新的内容放在两个钩子中去处理,这样可以减少不必要的http请求和DOM重复渲染,提升了不少性能

这篇关于1年Vue项目经验总结(持续更新中...)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!