1年Vue项目经验总结(持续更新中...)
2020/4/1 11:01:26
本文主要是介绍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二次封装的目的主要是三个方面:
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 (或者设置为 null 或 undefined ),promise 将被 resolve; 否则,promise 将被 rejecte |
validateStatus: function (status) { return status >= 200 && status < 300; // 默认的 }, |
maxRedirects | 定义在 node.js 中 follow 的最大重定向数目 | maxRedirects: 5, // 默认的 |
httpAgent | httpAgent 和 httpsAgent 分别在 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), }, ] }) 复制代码
在路由懒加载下,代码根据路由被拆分为不同的代码块,在切换进入相应的路由时,才对对应的代码块进行加载,加载更加高效了。
2.1.2 组件懒加载
components: { UpdateModal: resolve => { require(['./UpdateNormalTaskModal'], resolve); } }, 复制代码
在路由懒加载的前提下,进行组件懒加载的对比实验。
未使用组件懒加载:
整个页面为一个js,大小为718KB,加载耗时166ms。
在使用组件懒加载的时候:
整个页面被拆分为三个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'
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项目经验总结(持续更新中...)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-04package.json 文件位置在哪?-icode9专业技术文章分享
- 2024-10-01Craco.js学习:从入门到实践指南
- 2024-10-01Create-React-App学习:入门与实践指南
- 2024-10-01CSS-in-JS学习:从入门到实践指南
- 2024-09-30JSX语法学习:从入门到初步掌握
- 2024-09-30Mock.js学习:入门教程与实战演练
- 2024-09-30React Hooks学习:从入门到实践
- 2024-09-30受控组件学习:React中的基础入门教程
- 2024-09-29JS定时器教程:初学者必看指南
- 2024-09-29JS对象教程:初学者的全面指南