1、代码优化
1. 使用keep-alive缓存不活动的组件
keep-alive是一个抽象组件:它自身不会渲染一个DOM元素,也不会出如今父组件链中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。html
- 在动态组件中的应用
<keep-alive :include="whiteList" :exclude="blackList" :max="amount"> <component :is="currentComponent"></component> </keep-alive>
- 在vue-router中的应用
<keep-alive :include="whiteList" :exclude="blackList"> <router-view></router-view> </keep-alive>
include定义缓存白名单,keep-alive会缓存命中的组件;exclude定义缓存黑名单,被命中的组件将不会被缓存;
不少时候也能够配合路由的meta属性使用
前端
export default[ { path:'/', name:'home', components:Home, meta:{ keepAlive:true //须要被缓存的组件 }, { path:'/book', name:'book', components:Book, meta:{ keepAlive:false //不须要被缓存的组件 } ] <keep-alive> <router-view v-if="this.$route.meat.keepAlive"></router-view> <!--这里是会被缓存的组件--> </keep-alive> <keep-alive v-if="!this.$router.meta.keepAlive"></keep-alive> <!--这里是不会被缓存的组件-->
2. 使用路由懒加载
Vue 是单页面应用,可能会有不少的路由引入 ,这样使用 webpcak 打包后的文件很大,当进入首页时,加载的资源过多,页面会出现白屏的状况,不利于用户体验。若是咱们能把不一样路由对应的组件分割成不一样的代码块,而后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提升首屏显示的速度,可是可能其余的页面的速度就会降下来。vue
路由懒加载:webpack
export default new Router({ mode: 'history', routes: [ { path: '/', component: ()=>import('@/components/DefaultIndex') } ] })
详见另外一篇博客:前端优化中的路由懒加载ios
3. 图片懒加载
对于图片过多的页面,为了加速页面加载速度,因此不少时候咱们须要将页面内未出如今可视区域内的图片先不作加载, 等到滚动到可视区域后再去加载。这样对于页面加载性能上会有很大的提高,也提升了用户体验。咱们在项目中使用 Vue 的 vue-lazyload 插件:web
npm引入:npm i vue-lazyload -S CDN引入:[https://unpkg.com/vue-lazyload/vue-lazyload.js](https://unpkg.com/vue-lazyload/vue-lazyload.js)
使用:
main.js:
ajax
import Vue from 'vue' import App from './App.vue' import VueLazyload from 'vue-lazyload' Vue.use(VueLazyload) // or with options Vue.use(VueLazyload, { preLoad: 1.3, error: 'dist/error.png', loading: 'dist/loading.gif', attempt: 1 }) new Vue({ el: 'body', components: { App } })
template:vue-router
<ul> <li v-for="img in list"> <img v-lazy="img.src" > </li> </ul>
4. 使用节流防抖函数(性能优化)
那么在 vue 中怎么使用呢:
在公共方法中(如 untils.js 中),加入函数防抖和节流方法
vue-cli
// 防抖 export function _debounce(fn, delay) { var delay = delay || 200; var timer; return function () { var th = this; var args = arguments; if (timer) { clearTimeout(timer); } timer = setTimeout(function () { timer = null; fn.apply(th, args); }, delay); }; } // 节流 export function _throttle(fn, interval) { var last; var timer; var interval = interval || 200; return function () { var th = this; var args = arguments; var now = +new Date(); if (last && now - last < interval) { clearTimeout(timer); timer = setTimeout(function () { last = now; fn.apply(th, args); }, interval); } else { last = now; fn.apply(th, args); } } }
在须要使用的组件引用npm
import { _debounce } from "@/utils/public";
在 methods 中使用
methods: { // 改变场数 changefield: _debounce(function(_type, index, item) { // do something ... }, 200) }
应用:
函数防抖(debounce)
在事件被触发n秒后再执行回调,若是在这n秒内又被触发,则从新计时。
<body> <input type="text" id='unDebounce'> </body> </html> <script> //模拟一段ajax请求 function ajax(content){ console.log('ajax request ' + content) }; letinputa = document.getElementById('unDebounce'); function fn(e){ ajax(e.target.value) } //防抖函数,处理屡次被触发的事件,只执行最后一次 inputa.addEventListener('input', fn) </script>
看一下运行结果:
能够看到,咱们只要输入一个字符,就会触发此次ajax请求。不只从资源上来讲是很浪费的行为,并且实际应用中,用户也是输出完整的字符后,才会请求。下面咱们优化一下:
<body> <input type="text" id='unDebounce'> </body> </html> <script> //防抖函数 function _debounce(fn, delay) { var delay = delay || 200; var timer; return function () { var th = this; var args = arguments; if (timer) { clearTimeout(timer); } timer = setTimeout(function () { timer = null; fn.apply(th, args); }, delay); }; } //模拟一段ajax请求 function ajax(content){ console.log('ajax request ' + content) }; let inputa = document.getElementById('unDebounce'); function fn(e){ ajax(e.target.value) } //防抖函数,处理屡次被触发的事件,只执行最后一次 inputa.addEventListener('input', _debounce(fn,1000)) </script>
咱们加入了防抖之后,当你在频繁的输入时,并不会发送请求,只有当你在指定间隔内没有输入时,才会执行函数。若是中止输入可是在指定间隔内又输入,会从新触发计时。
我的理解 函数防抖就是法师发技能的时候要读条,技能读条没完再按技能就会从新读条。
函数节流(throttle)
规定在一个单位时间内,只能触发一次函数。若是这个单位时间内触发屡次函数,只有一次生效。
<body> <input type="text" id='unDebounce'> </body> </html> <script> //节流函数 function _throttle(fn, interval) { var last; var timer; var interval = interval || 200; return function () { var th = this; var args = arguments; var now = +new Date(); if (last && now - last < interval) { clearTimeout(timer); timer = setTimeout(function () { last = now; fn.apply(th, args); }, interval); } else { last = now; fn.apply(th, args); } } } //模拟一段ajax请求 function ajax(content){ console.log('ajax request ' + content) }; let inputa = document.getElementById('unDebounce'); function fn(e){ ajax(e.target.value) } //防抖节流,不管你输入多块,每隔1秒钟执行一次 inputa.addEventListener('input', _throttle(fn,1000)) </script>
无论咱们设定的执行时间间隔多小,老是1s内只执行一次。
我的理解 函数节流就是fps游戏的射速,就算一直按着鼠标射击,也只会在规定射速内射出子弹。
总结
函数防抖和函数节流都是防止某一时间频繁触发,可是这两兄弟之间的原理却不同。
函数防抖是某一段时间内只执行一次,而函数节流是间隔时间执行。
结合应用场景
debounce
- search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
throttle
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 拖拽事件,每拖动1px都会触发onmousemove(能够用throttle优化,每秒触发一次)
- 监听滚动事件,好比是否滑到底部自动加载更多,用throttle来判断
5. v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
- v-for 遍历必须为 item 添加 key
在列表数据进行遍历渲染时,须要为每一项 item 设置惟一 key 值,方便 Vue.js 内部机制精准找到该条列表数据。当 state
更新时,新的状态值和旧的状态值对比,较快地定位到 diff 。
- v-for 遍历避免同时使用 v-if
v-for 比 v-if 优先级高,若是每一次都须要遍历整个数组,将会影响速度,尤为是当之须要渲染很小一部分的时候,必要状况下应该替换成
computed 属性。
推荐:
<template> <div class="home"> <ul> <li v-for="user in activeUsers" :key="user.id"> { { user.name }} </li> </ul> </div> </template> <script> export default { data(){ return { users:[{ id:1,name:'zhangsan',isActive:true},{ id:2,name:'lisi',isActive:true},{ id:3,name:'wangwu',isActive:false},{ id:4,name:'maliu',isActive:true},] } }, computed: { activeUsers: function () { // [js 的filter()方法](https://www.cnblogs.com/qiu2841/p/8961017.html) return this.users.filter(function (user) { return user.isActive }) } } } </script>
不推荐:
<ul> <li v-for="user in users" v-if="user.isActive" :key="user.id"> { { user.name }} </li> </ul>
6. v-if 和 v-show 区分使用场景
v-if 是 真正 的条件渲染,由于它会确保在切换过程当中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:若是在初始渲染时条件为假,则什么也不作——直到条件第一次变为真时,才会开始渲染条件块。
v-show就简单得多, 无论初始条件是什么,元素老是会被渲染,而且只是简单地基于 CSS 的 display 属性进行切换。
因此,v-if 适用于在运行时不多改变条件,不须要频繁切换条件的场景; v-show则适用于须要很是频繁切换条件的场景。
7. computed 和 watch 区分使用场景
computed: 是计算属性,依赖其它属性值,而且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会从新计算 computed 的值;
watch: 更多的是「观察」的做用,相似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操做;
运用场景:
-
当咱们须要进行数值计算,而且依赖于其它数据时,应该使用 computed,由于能够利用 computed 的缓存特性,避免每次获取值时,都要从新计算;
-
当咱们须要在数据变化时执行异步或开销较大的操做时,应该使用 watch,使用 watch 选项容许咱们执行异步操做 ( 访问一个 API ),限制咱们执行该操做的频率,并在咱们获得最终结果前,设置中间状态。这些都是计算属性没法作到的。
8. 长列表性能优化
Vue 会经过 Object.defineProperty 对数据进行劫持,来实现视图响应数据的变化,然而有些时候咱们的组件就是纯粹的数据展现,不会有任何改变,咱们就不须要 Vue 来劫持咱们的数据,在大量数据展现的状况下,这可以很明显的减小组件初始化的时间,那如何禁止 Vue 劫持咱们的数据呢?能够经过 Object.freeze 方法来冻结一个对象,一旦被冻结的对象就不再能被修改了。
export default { data: () => ({ users: { } }), async created() { const users = await axios.get("/api/users"); this.users = Object.freeze(users); } };
9. 事件的销毁
Vue 组件销毁时,会自动清理它与其它实例的链接,解绑它的所有指令及事件监听器,可是仅限于组件自己的事件。 若是在 js 内使用 addEventListene 等方式是不会自动销毁的,咱们须要在组件销毁时手动移除这些事件的监听,以避免形成内存泄露,如:
created() { addEventListener('click', this.click, false) }, beforeDestroy() { removeEventListener('click', this.click, false) }
10. 第三方插件的按需引入
咱们在项目中常常会须要引入第三方插件,若是咱们直接引入整个插件,会致使项目的体积太大,咱们能够借助 babel-plugin-component ,而后能够只引入须要的组件,以达到减少项目体积的目的。如下为项目中引入 element-ui 组件库为例:
(1)首先,安装 babel-plugin-component :
npm install babel-plugin-component -D `` (2)而后,将 .babelrc 修改成: ```js { "presets": [["es2015", { "modules": false }]], "plugins": [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }
(3)在 main.js 中引入部分组件:
import Vue from 'vue'; import { Button, Select } from 'element-ui'; Vue.use(Button) Vue.use(Select)
2、webpack打包优化
详见我上一篇博客vue-cli4打包优化(webapck优化)
最后别忘记 「点赞」