任何项目达到一定规模, 往往会带来性能问题, 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
来源: http://www.jianshu.com/p/ec2352305ef5