优化清单:
1.路由模块按需加载
2.组件懒加载
3.Object.freeze() 冻结不再变更的对象
4.开启productionGzip 压缩
5.合理使用keep-alive保留组件状态,避免重新渲染
6.v-if与v-show根据具体业务场景适当选取
7.图片使用与加载优化
8.大数据列表使用vue-virtual-scroll-list优化
9.配置 externals 使库文件采用cdn加载
具体措施:
1.路由懒加载和组件懒加载
作用:
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了
操作:
使用ES 提出的import方法,(------最常用------)
路由懒加载:
const HelloWorld = ()=>import('需要加载的模块地址')
指定chunkGroup的方式:
const Main = () => import(/* webpackChunkName: "chunk-main" */ '@/page/Main.vue')
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const HelloWorld = ()=>import("@/components/HelloWorld")
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component:HelloWorld
}
]
})
组件懒加载:
<template>
<div class="hello">
<One-com></One-com>
</div>
</template>
<script>
const One = ()=>import("./one");
export default {
components:{
"One-com":One
},
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
2.Object.freeze() 冻结不再变更的对象
作用:
可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象
操作:
const obj = {
prop: 42
};
Object.freeze(obj);
obj.prop = 33;
// Throws an error in strict mode
console.log(obj.prop);
// expected output: 42
3.使用keep-alive保留组件状态,避免重新渲染
作用:
<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
操作:
<!-- 基本 -->
<keep-alive>
<component :is="view"></component>
</keep-alive>
<!-- 多个条件判断的子组件 -->
<keep-alive>
<comp-a v-if="a > 1"></comp-a>
<comp-b v-else></comp-b>
</keep-alive>
<!-- 和 `<transition>` 一起使用 -->
<transition>
<keep-alive>
<component :is="view"></component>
</keep-alive>
</transition>
4.v-if与v-show根据具体业务场景适当选取
1、实现方式
- v-if是根据后面数据的真假值判断直接从Dom树上删除或重建元素节点
- v-show只是在修改元素的css样式,也就是display的属性值,元素始终在Dom树上。
2、编译过程
- v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;
- v-show只是简单的基于css切换;
3、编译条件
- v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译;
- v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素始终被保留;
4、性能消耗
- v-if有更高的切换消耗,不适合做频繁的切换;
- v-show有更高的初始渲染消耗,适合做频繁的额切换;
5.图片使用与加载优化
1.在支持webp 图片格式的浏览器上使用webp
2.使用 iconfont
3.SVG替换png,jpg
4.小图片直接使用base64(Webpack rule url-loader 已处理)
5.尽量主动设置img 标签的width ,height 属性
6.大数据列表使用vue-virtual-scroll-list优化
原理:
虚拟列表做的事情,就是按需渲染。只需要渲染当前视图需要显示的几个条目和即将滚动到的几个条目。在开发者工具中可以发现,DOM 中只存在这么几条列表项,当滚动的时候会替换这几项。所以大大节省了系统资源,提升了用户体验。
核心实现
this.$slots.default类型为数组,存储的是此组件两标签中的内容,在此特指大量的列表项。
通过 Vue 数组的 filter 方法,筛选出处于当前视图中的几个项,选择性的只渲染出这几个在 DOM 中。渲染是依据 Vue 的 render 函数来动态定义组件。
export default {
name: 'item',
props: [
'item',
'k'
],
render: function (createElement) {
return createElement(
'div',
this.$slots.default.filter(function (slot, index) {
return index > 5 && index < 10
})
)
}
}
操作
1.安装
npm install vue-virtual-scroll-list --save
2.使用
<template>
<div>
<virtual-list :size="40" :remain="8">
<item v-for="item of items" :key="item.id" />
</virtual-list>
</div>
</template>
<script>
import item from '../item.vue'
import virtualList from 'vue-virtual-scroll-list'
export default {
data () {
return {
items: [ {id: 1}, {id: 2}, {id: 3}, ... ]
}
},
components: { item, 'virtual-list': virtualList }
}
</script>
7.配置 externals 使库文件采用cdn加载
原理:
利用 webpack 的 externals 属性 。文档
官网的解释 :防止 将某些 import 的包(package) 打包 到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)。
通俗的解释:让某些资源包即使不在本地npm安装,通过 script 标签引入后也能使用
操作:
操作:
- 首先在模板文件
index.html
中添加以下内容
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>XXXX平台</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/element-ui/2.4.1/theme-chalk/index.css">
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.17.0/axios.min.js"></script>
<script src="https://cdn.bootcss.com/element-ui/2.4.1/index.js"></script>
<!-- built files will be auto injected -->
</body>
</html>
复制代码
注意!版本号要与 package.json
中的版本号一致
- 修改
build/webpack.base.conf.js
module.exports = {
...
externals: {
'vue': 'Vue',
'vuex': 'Vuex',
'vue-router': 'VueRouter',
'axios': 'axios',
'element-ui': 'ELEMENT'
}
...
}
复制代码
注意!这里 axios
变量名要使用 axios
注意!这里 element-ui
变量名要使用 ELEMENT
,因为element-ui
的 umd
模块名是 ELEMENT
- 修改
src/router/index.js
// import Vue from 'vue'
import VueRouter from 'vue-router'
// 注释掉
// Vue.use(VueRouter)
...
}
复制代码
- 修改
src/store/index.js
...
// 注释掉
// Vue.use(Vuex)
...
}
复制代码
- 修改
src/main.js
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
// 注释掉
// import 'element-ui/lib/theme-chalk/index.css'
// router setup
import router from './router'
// Vuex setup
import store from './store'
Vue.use(ElementUI)
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App }
})
开了一个大前端技术交流群,也可直接加我微信入群(mokinzhao)