Vue.js 应用性能优化的几条建议,最后一条你用过吗?
任何项目达到一定规模,往往会带来性能问题,Vue.js 也不例外。本文简单介绍几个小技巧,帮你在一定程度上对项目做性能上的优化。
图片懒加载
如果应用里需要展示大量图片,比如电商网站,通常的做法是懒加载图片。懒加载的基本原理是提前准备好图片 URL,当图片真正进入可视范围时才去加载。可以手动实现懒加载机制,不过更方便的是直接用现成的插件,比如 [vue-lazyload]
安装:
npm i vue-lazyload -S
入口文件里引入:
// in main.js
import Vue from 'vue'
import App from './App.vue'
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
new Vue({
el: '#app',
components: {
App
}
})
在模板里使用该插件提供的指令:
<ul>
<li v-for="img in list">
<img v-lazy="img.src">
</li>
</ul>
按需使用第三方库
如今前端开发生态可谓是蓬勃发展,各种第三方库应有尽有。但是,项目引入过多的第三方库也会增大项目体积,带来性能问题。以 Bootstrap 为例,如果你只是用一下它的响应式机制,还不如自己手写相关的 CSS,也不会太复杂,完全没有必要引入整个库。再比如 Moment.js,如果只是简单做下日期时间格式化,自己写个工具函数也就几行代码,引入庞大的完整包也是大材小用。这些库为了普适性,提供了尽可能多的功能,但你的项目可能只用了极少部分。我们不鼓励重复造轮子,但是要按需引入。现在很多库都提供了 ES 模块化的方式,也可以做到这一点。
路由懒加载
路由懒加载也可以提高入口页面的加载速度,因为很多路由页面在多数情况下并没有被访问,在打包的时候放到单独的文件里可以减少入口页的体积。路由懒加载是通过 webpack 的动态 import
来实现的。
// in router.js
import Home from '@/views/Home.vue'; // 静态 import
const About = () => import('@/views/About.vue'); // 动态 import
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
})
另外,这些懒加载的路由还可以分组,让相关性模块的多个路由页面打包到同一个 chunk
,算是一种折中方案:既实现了按需加载,又不会过于碎片化。适用于子路由页面。
// in router.js
import Home from '@/views/Home.vue'; // traditonal imports
import User from '@/views/User.vue';
const About = () => import('@/views/About.vue'); // dynamic import
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/user/:id', component: User,
children: [
{
path: '/settings',
component: () => import(/* webpackChunkName: "user" */ '@/views/UserSettings')
},
{
path: '/articles',
component: () => import(/* webpackChunkName: "user" */ '@/views/UserArticles')
}
]
}
]
})
这是通过 webpack 的注释语法/* webpackChunkName: "user" */
实现的,webpackChunkName
相同的路由会打进同一个 chunk
文件。
不要滥用 Vuex store
Vuex 几乎是 Vue.js 项目全局状态管理的标配,以至于有些人一上来就把接口请求的数据全部往 store 里塞。时间一长,store 里的字段搞得一团糟。所谓全局状态,应该是在多个组件里都要用到的数据。经验值是少于三个组件的话,就没必要放在 Vuex 里了。store 过大会影响性能,也不方便管理。
大列表禁用响应式功能
默认情况下,定义在 Vue 组件data
里的数据都是响应式的,这种机制方便了数据绑定,当数据变化时界面得到自动更新。但有时候我们只是将数据显示到界面上,之后也不会改变它。这种情况下我们根本用不上响应式机制,而实现响应式是有性能代价的,特别是对于大对象和大列表。
export default {
data: () => ({
users: {}
}),
async created() {
const users = await axios.get("/api/users");
this.users = users;
}
};
上面代码里的 users
可能包含了非常多的数据,这样的对象数组要实现响应式会比较耗时。如果只是为了显示,不用于编辑,可以通过Object.freeze()
禁用对象的响应式特性。
export default {
data: () => ({
users: {}
}),
async created() {
const users = await axios.get("/api/users");
this.users = Object.freeze(users);
}
};
在 Vuex 里也一样:
const mutations = {
setUsers(state, users) {
state.users = Object.freeze(users);
}
};
如果确实需要修改数据,也可以重新生成数组:
state.users = Object.freeze([...state.users, user]);
根据测试,优化后的代码,对于同样的数据量,组件初始化的时间从几百毫秒缩短到几毫秒。
总结
以上是 Vue.js 应用代码优化的一点经验之谈,希望对你有用。欢迎在评论区留言,补充更多优化方法!
看到这个颇有气质的 logo,不来关注下吗?
image