代码优化
1、使用keep-alive缓存不活动的组件
keep-alive是一个抽象组件:它自身不会渲染一个DOM元素,也不会出现在父组件中;使用keep-alive包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
在动态组件中
<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是单页面应用,可能会有很多的路由引入,这样使用webpack打包后的文件很大,当进入首页时,加载的资源过多,页面回出现白屏的情况,不利于用户体验。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更高效。这样会提高首屏显示的速度,但是可能其他的页面速度就会降下来。
{
path: '/Student',
name: 'Student',
component: () => import( '../views/user/student.vue'),
},
3、图片懒加载
对于图片过多的页面,为了加速页面加载速度。所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。这样对于页面加载性能上会有很大的提升,也提高了用户体验。我们在项目中使用 Vue 的 vue-lazyload插件:
npm引入:npm i vue-lazyload -S
<ul>
<li v-for="img in list">
<img v-lazy="img.src" >
</li>
</ul>
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
}
})
4、使用节流防抖函数(性能优化)
防抖:
在事件被触发n秒后在执行回调,如果在这n秒内又被触发,需要重新计时。
节流:
规定在一个单位时间 内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
总结:
函数防抖和函数节流都是防止某一时间频繁触发,但是这两兄弟之间的原理却不一样。
函数防抖是某一段时间内只执行一次,而函数节流是间隔时间执行。
应用场景
防抖:
1、search搜索联想,用户在不断输入值时,用防抖节流来节约请求资源。
2、window触发resize的时候,不断地调整浏览器窗口的大小就会不断地触
发这个事件,用防抖来让它只触发一次
节流:
1、鼠标不断点击触发,mousedown(单位时间内只触发一次)。
2、拖拽事件,每拖动1px都会触发onmousemove(可以用节流优 化,每秒触发一次)。
3、监听滚动事件,比如是否滑动到底部自动加载更多,用节流来判断。
// 防抖
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);
}
}
}
在需要的组件引用
import { _debounce } from "@/utils/public";
methods: {
// 改变场数
changefield: _debounce(function(_type, index, item) {
// do something ...
}, 200)
}
5、v-for遍历必须为item添加key,且避免同时使用v-if
v-for 遍历必须为item添加key
在列表数据进行遍历渲染时,需要为每一项item,设置唯一key值,方便Vue.js内部机制精准找到这条列表数据。
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>
6、v-if和v-show区分使用场景
v-if 是真正地条件渲染,因为它会确保在切换过程中条件块内地事件监听和子组件适当地销毁和重建;也是惰性的:如果在初始渲染时条件为假,就什么也不做,直到条件第一次变为真时,才会开始渲染条件。
v-show就简单得多,不管初始条件是什么,元素总是会被渲染,并且只是简单地基于css的display属性进行切换。
v-if适用于在运行时很少改变条件,不需要不能规范切换条件的场景;v-show适用于需要频繁切换条件的场景。
7、computed和watch区分使用场景
computed:是计算属性,依赖其他属性值,有缓存值,只有它的依赖值发生改变,下次获取computed的值时才会重新计算。
watch:起到(观察)的作用,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作;
使用场景
需要进行数值计算,并且依赖于其他数据时,应该使用computed,因为可以利用computed的缓存特性,避免每次获取值时,都要重新计算;
需要在数据变化时执行异步或开销较大的操作时,应该使用用watch,使用watch选项允许执行异步操作(访问一个API)限制执行该操作的频率,在最终结果前,设置中间状态,这些都是计算属性做不到的。
8、长列表性能优化
Vue通过Object.defineProperty对数据进行劫持,来实现视图响应数据的变化,但是有些时候组件就是纯粹的数据展示,不会有任何变化,那就不需要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 ,然后可以只引入需要的组件,以达到减小项目体积的目的。
首先安装 babel-plugin-component ,
npm install babel-plugin-component -D
然后,将 .babelrc 修改为:
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
在 main.js 中引入部分组件:
import Vue from 'vue';
import { Button, Select } from 'element-ui';
Vue.use(Button)
Vue.use(Select)