代码优化
1.使用keep-alive缓存不活动的组件实例。
keel-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 是单页面应用,可能会有很多的路由引入 ,这样使用 webpcak 打包后的文件很大,当进入首页时,加载的资源过多,页面会出现白屏的情况,不利于用户体验。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来。
路由懒加载:
export default new Router({
mode: 'history',
routes: [
{
path: '/',
component: ()=>import('@/components/DefaultIndex') }
]
})
3.图片懒加载
对于图片过多的页面,为了提高页面的加载速度,所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载,等到图片进入可视区域内的时候再去加载。这样对于页面加载性能上会有很大的提升,也提高了用户的体验,使用图片懒加载我们需要在项目中使用Vue的vue-lazyload
插件:
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:
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:
<ul>
<li v-for="img in list">
<img v-lazy="img.src" >
</li>
</ul>
4.使用防抖节流函数(性能优化)
那么怎么在Vue中使用呢?
在公共方法(untils.js中),加入函数防抖和节流方法:
// 防抖
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中使用:
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则适用于需要非常频繁切换条件的场景。