vue性能优化

一、webpack层面优化

CDN加载方式替换import方式

原理:

浏览器从服务器上下载 CSS、js 和图片等文件时都要和服务器连接,而大部分服务器的带宽有限,如果超过限制,网页就半天反应不过来。而 CDN 可以通过不同的域名来加载文件,从而使下载文件的并发连接数大大增加,且CDN 具有更好的可用性,更低的网络延迟和丢包率 。

操作:

// 文件:./src/index.html
<script src="https://cdn.bootcss.com/vue/2.5.3/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vuex/3.1.0/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/clipboard.js/2.0.4/clipboard.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>

图片base64转码

目的:图片转base64后,图片打包进dist/app.js中,随js一起加载,减少http请求次数。图片转成base64后,文件体积变大了大约1/3左右

注意:

  • 文件的base64编码存储到了js文件中
  • vue-webpack模板的默认设置限制了转码的文件大小为10000B以下
  • 静态文件目录中的所有文件不会被转码,也就是/static下的所有文件都不会被转码
  • 如果所有图片均转码为base64,那么很容易造成存储base64的js文件过大,一方面会造成资源加载时间过长的白屏问题,另一方面也会给js解释器带来非常大的负担,这样反而起不到优化的作用,而且会非常影响体验
  • 如果你非要让所有图片转为base64,可以修改webpack中的url-loader配置

js/css文件压缩

1.js文件切割

2.js文件压缩

3.css文件切割加载

4.css文件压缩


图片压缩


公共部分抽离

1.公共js文件抽离


2.公共css文件抽离

文件:./src/app.vue
<style lang="less">
    @import '~@/assets/styles/common.less';
</style>

3.less公共变量全局设置

方案一:全局配置

文件: build/utils.js

// cssLoaders中新增lessResourceLoader函数
// 修改return中less: generateLoaders('less')改为less: lessResourceLoader()
// 将全局less文件引入resources参数中
exports.cssLoaders = function (options) {
    
  function lessResourceLoader(){
    var loaders = [
        cssLoader,
        'less-loader',
        {
            loader: 'sass-resources-loader',
            options: {
                resources: [
                    // 引入全局less文件
                    path.resolve(__dirname, '../src/assets/styles/variables.less')
                ]
            }
        }
    ];
    if (options.extract) {
        return ExtractTextPlugin.extract({
            use: loaders,
            fallback: 'vue-style-loader'
        })
    } else {
        return ['vue-style-loader'].concat(loaders)
    }
  }
  
  return {
    // less: generateLoaders('less'),
    less: lessResourceLoader()
  }
}

方案二:在每个vue文件style标签中import引入

import '~@/assets/styles/variables.less'

externals配置不被打包的js文件

文件: ./build/webpack.base.config.js

externals:{
    'vue': 'Vue',
    'vue-router': 'VueRouter',
    'vuex':'Vuex',
    'clipboard':'Clipboard',
    'axios':'axios',
    'vueLazyload':'LazyContainer'
},
键值对中的值为三方件源码中抛出的全局变量

设置是否生成source文件

文件:./build/webpack.prod.config.js



二、业务代码层面优化

事件销毁

 created() {
   addEventListener('click', this.click, false)
 },
 beforeDestroy() {
   removeEventListener('click', this.click, false)
 }


图片懒加载

原理:图片过多,优先加载可视区域内的图片

方案一:插件

// 安装vue-lazyload插件
npm install vue-lazyload --save-dev

// main.js中引入并全局注册
import VueLazyload from 'vue-lazyload'

Vue.use(VueLazyload, {
    preLoad: 1.3,
    loading: require('@/assets/p/90_90.png'),
    attempt: 3,
    try: 2  //加载图片数量
})

preLoad:1.3, //类型Number,默认1.3.表示lazyload的元素距离页面底部距离的百分比.计算值为(preload - 1).
attempt:3, //图片加载失败后的重试次数.默认为3.
error:'', //类型string.图片加载失败后的显示的失败图片路径.
loading:'', //类型string.图片正在加载中显示的loading图片的路径.
listenEvents:[], //类型array.默认['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove'].即是在监听上述事件中,判断图片是否在preload的位置.如果你不想在那么多事件中判断,可以指定一个或者几个.例如如果你给这个属性只指定['touchmove'].那么scroll 屏幕不会加载图片,只有手指滑动屏幕才会加载图片.
adapter:'', //注册img的loading,loaded,error三个状态的回调函数,参数会暴露懒加载的img元素,可以对其进行操作.
filter:'', // img未加载之前,解析到src 的时候注册的回调函数.可以在加载图片之前,对src进行修改.注册在filter下的所有的函数都会执行
lazyComponent:false,//类型Boolean.是否启用懒加载组件.组件中的内容只有在出现在preload的位置中才会加载组件.这个lazyloadComponent 组件有个缺点就是,组件在加载前是什么都不渲染的,这样子的话,有可能会影响布局,以及加载前到加载后的切换不好,有点突兀和生硬.挖坑(vue懒加载组件)
observer:false, //是否启用IntersectionObserver,这个api有兼容问题
observerOptions:{} //默认{ rootMargin: '0px', threshold: 0.1 }主要是我对这个pai不熟,按照vue-lazyload的说法是开启之后,对很多节点的情况会优化性能.挖坑吧
    
    
// 在img标签中用v-lazy代替src
<img v-lazy="hotPurchaseImgList[index].imgUrl">

本地模拟

// 数据返回前渲染空页面
// 数据返回后,渲染正常页面
<listX  @isShowListX="getIsShowListX" v-if="isShowListX"/>
<listXP v-else="isShowListXP"/>

路由懒加载

 const classify =
  {
    path: '/classify',
    name: 'classify',
    meta: { title: '分类' },
    redirect: '/classify/index',
    component: () => import('@/components/router'),
    children: [{
      path: 'index',
      name: 'classifyIndex',
      meta: { title: '分类' },
      component: () => import('@/view/classify/index')
    }, {
      path: 'list',
      name: 'classifyList',
      meta: { title: '分类' },
      component: () => import('@/view/classify/classListForItem')
    }]
  }
export default classify

三方件按需加载

方案一:babel-plugin-import按需引入 (以mand-mobile为例)

 // 安装babel-plugin-import插件
 npm install babel-plugin-import -D
 
 // 修改.babelrc文件
 {
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

方案二:babel-plugin-component按需引入 (以element-ui为例)

 // 安装babel-plugin-component插件
 npm install babel-plugin-component -D
 
 // 修改.babelrc文件
 {
   "plugins": [
     ["component", {
       "libraryName": "element-ui",
       "libraryDirectory": "lib",
       "styleLibraryName": "theme-chalk"
     }]
   ]
 }
 
 // main.js中按需引入
 import Vue from 'vue';
 import { Button, Select } from 'element-ui';

 Vue.use(Button)
 Vue.use(Select)

显示类数据冻结双向绑定,减少组件初始化时间

原理: Vue双向绑定采用Object.defineProperty进行数据劫持实现,针对显示类数据,无需进行数据劫持,采用Object.freeze冻结对象

 export default {
  data: () => ({
    users: {}
  }),
  async created() {
    const users = await axios.get("/api/users");
    this.users = Object.freeze(users);
  }
 };

三、服务器端渲染 & 预渲染

posted @ 2019-10-31 22:17  南华秋水  阅读(483)  评论(0编辑  收藏  举报