亚洲欧洲日产国码直播而 v-show 在要求变化的工夫
发布日期:2022-09-23 04:39    点击次数:74
女人高潮叫床流水视频亚洲欧洲日产国码直播

 性能优化,是每一个设备者都会遭受的问题,止境是当今越来越爱好体验,以及竞争越来越好坏的环境下,关于咱们设备者来说,只完成迭代,把功能做好是远远不够的,最蹙迫的是把居品做好,让更多人知足使用,让用户用得更爽,这不亦然咱们设备者价值与才略的体现吗。

爱好性能问题,优化居品的体验,比起改几个无关痛痒的 bug 要有价值得多

本文纪录了我在 Vue 名堂日常设备中的一些小妙技,鬼话未几说,咱们脱手吧

一. 长列表性能优化 1. 不做反映式

比如会员列表、商品列表之类的,仅仅纯正的数据展示,不会有任何动态改变的场景下,就不需要对数据做反映化处理,不错大大普及渲染速率

比如使用 Object.freeze() 冻结一个对象,MDN的形容是 该设施冻结的对象弗成被修改;即弗成向这个对象添加新属性,弗成删除已有属性,弗成修改该对象已有属性的可成列性、可成就性、可写性,以及弗成修改已有属性的值,以及该对象的原型也弗成被修改 

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

Vue2 的反映式源码地址:src/core/observer/index.js - 144行 是这么的 

export function defineReactive (...){     const property = Object.getOwnPropertyDescriptor(obj, key)     if (property && property.configurable === false) {         return    }     ... } 

不错看到一脱手就判断 configurable 为 false 的径直复返不做反映式处理

configurable 为 false 示意这个属性是弗成被修改的,而冻结的对象的 configurable 即是为 false

Vue3 里则是添加了反映式flag,用于象征想法对象类型

2. 诬捏改换

如果是大数据很长的列表,沿途渲染的话一次性创建太多 DOM 就会止境卡,这时就不错用诬捏改换,只渲染少部分(含可视区域)区域的推行,然后改换的工夫,禁止替换可视区域的推行,模拟出改换的恶果 

<recycle-scroller   class="items"   :items="items"   :item-size="24"  >   <template v-slot="{ item }">     <FetchItemView       :item="item"       @vote="voteItem(item)"     />   </template>  </recycle-scroller> 

参考 vue-virtual-scroller、vue-virtual-scroll-list

旨趣是监听改换事件,动态更新需要流露的 DOM,并推测出在视图中的位移,这也意味着在改换过程需要及时推测,有一定资本,是以如果数据量不是很大的情况下,用普通的改换就行

二. v-for 遍历幸免同期使用 v-if

为什么要幸免同期使用 v-for 和 v-if

在 Vue2 中 v-for 优先级更高,是以编译过程中会把列表元素沿途遍历生成诬捏 DOM,再来通过 v-if 判断合适要求的才渲染,就会形成性能的陡然,因为咱们但愿的是不合适要求的诬捏 DOM都不要生成

在 Vue3 中 v-if 的优先级更高,就意味着当判断要求是 v-for 遍历的列表中的属性的话,v-if 是拿不到的

是以在一些需要同期用到的场景,就不错通过推测属性来过滤一下列表,如下 

<template>     <ul>       <li v-for="item in activeList" :key="item.id">        {{ item.title }}       </li>     </ul>  </template>  <script>  // Vue2.x  export default {     computed: {       activeList() {         return this.list.filter( item => {           return item.isActive        })      }    }  }  // Vue3  import { computed } from "vue";  const activeList = computed(() => {   return list.filter( item => {     return item.isActive  })  })  </script
三. 列表使用独一 key

比如有一个列表,咱们需要在中间插入一个元素,在不使用 key 大要使用 index 手脚 key 会发生什么变化呢?先看个图

如图的 li1 和 li2 不会再行渲染,这个莫得争议的。而 li3、li4、li5 都会再行渲染

因为在不使用 key 大要列表的 index 手脚 key 的工夫,每个元素对应的位置关系都是 index,上图中的收尾径直导致咱们插入的元素到背面的沿途元素,对应的位置关系都发生了变更,是以在 patch 过程中会将它们十足引申更新操作,再再行渲染。

这可不是咱们想要的,咱们但愿的是渲染添加的那一个元素,其他四个元素不做任何变更,也就不要再行渲染

而在使用独一 key  的情况下,每个元素对应的位置关系即是 key,来看一下使用独一 key 值的情况下

这么如图中的 li3 和 li4 就不会再行渲染,因为元素推行没发生改变,对应的位置关系也莫得发生改变。

这亦然为什么 v-for 必须要写 key,而且不提议设备中使用数组的 index 手脚 key 的原因

四. 使用 v-show 复用 DOM

v-show:是渲染组件,然后改变组件的 display 为 block 或 none  v-if:是渲染或不渲染组件

是以关于不错平日改变要求的场景,就使用 v-show 温和性能,止境是 DOM 结构越复杂收益越大

不外它也有缺点, 酵素即是 v-show 在一脱手的工夫,系数分支里面的组件都会渲染,对应的人命周期钩子函数都会引申,而 v-if 只会加载判断要求射中的组件,是以需要把柄不同场景使用合适的教导

比如底下的用 v-show 复用DOM,比 v-if/v-else 恶果好 

<template>   <div>     <div v-show="status" class="on">       <my-components />     </div>     <section v-show="!status" class="off">       <my-components >     </section>  </div>  </template

旨趣即是使用 v-if 当要求变化的工夫,触发 diff 更新,发现新旧 vnode 不一致,就会移除通盘旧的 vnode,再再行创建新的 vnode,然后创建新的 my-components 组件,又会经验组件自身运行化,render,patch 等过程,而 v-show 在要求变化的工夫,新旧 vnode 是一致的,就不会引申移除创建等一系列经由

五. 无景色的组件用函数式组件

关于一些纯展示,莫得反映式数据,莫得景色处置,也毋庸人命周期钩子函数的组件,咱们就不错建立成函数式组件,提高渲染性能,因为会把它当成一个函数来处理,是以支出很低

旨趣是在 patch 过程中关于函数式组件的 render 生成的诬捏 DOM,不会有递归子组件运行化的过程,是以渲染支出会低好多

它不错继承 props,但是由于不会创建实例,是以里面弗成使用 this.xx 获得组件属性,写法如下 

<template functional>   <div>     <div class="content">{{ value }}</div>   </div>  </template>  <script>  export default {   props: ['value']  }  </script>  // 大要  Vue.component('my-component', {   functional: true, // 示意该组件为函数式组件   props: { ... }, // 可选   // 第二个参数为荆棘文,莫得 this   render: function (createElement, context) {     // ...  }  }) 
六. 子组件分割

先看个例子 

<template>   <div :style="{ opacity: number / 100 }">     <div>{{ someThing() }}</div>   </div>  </template>  <script>  export default {   props:['number'],大大香蕉伊人久久爱   methods: {     someThing () { /* 耗时任务 */ }  }  }  </script

上头这么的代码中,每次父组件传过来的 number 发生变化时,每次都会再行渲染,况兼再行引申 someThing 这个耗时任务

是以优化的话一个是用推测属性,因为推测属性自身有缓存推测收尾的特点

第二个是拆分红子组件,因为 Vue 的更新是组件粒度的,天然第次数据变化都会导致父组件的再行渲染,但是子组件却不会再行渲染,因为它的里面莫得任何变化,耗时任务天然也就不会再行引申,因此性能更好,优化代码如下 

<template>  <div>     <my-child />  </div>  </template>  <script>  export default {  components: {     MyChild: {      methods: {         someThing () { /* 耗时任务 */ }       },        render (h) {        return h('div', this.someThing())     }    }  }  }  </script
七. 变量土产货化

节略说即是把会屡次援用的变量保存起来,因为每次看望 this.xx 的工夫,由于是反映式对象,是以每次都会触发 getter,然后引申依赖集中的关连代码,如果使用变量次数越多,性能天然就越差

从需求上说在一个函数里一个变量引申一次依赖集中就够了,然而好多人习尚性的在名堂中无数写 this.xx,而忽略了 this.xx 背后做的事,就会导致性能问题了

比如底下例子 

<template>    <div :style="{ opacity: number / 100 }"> {{ result  }}</div>  </template>  <script>  import { someThing } from '@/utils'  export default {   props: ['number'],  computed: {      base () { return 100 },      result () {       let base = this.base, number = this.number //   保存起来        for (let i = 0; i < 1000; i++) {        number += someThing(base) // 幸免平日援用  this.xx       }        return number     }  }  }  </script
八. 第三方插件按需引入

比如 Element-UI 这么的第三方组件库不错按需引入幸免体积太大,止境是名堂不大的情况下,更莫得必要美满引入组件库 

// main.js import Element3 from "plugins/element3";  Vue.use(Element3)  // element3.js  // 美满引入  import element3 from "element3";  import "element3/lib/theme-chalk/index.css";   // 按需引入  // import "element3/lib/theme-chalk/button.css";  // ...  // import {   // ElButton,   // ElRow,   // ElCol,   // ElMain,   // .....  // } from "element3";  export default function (app) {   // 美满引入   app.use(element3)    // 按需引入   // app.use(ElButton);  } 
九. 路由懒加载

咱们默契 Vue 是单页应用,是以如果莫得效懒加载,就会导致参预首页时需要加载的推行过多,工夫过长,就会出现长工夫的白屏,很不利于用户体验,SEO 也不友好

是以不错去用懒加载将页面进行辞别,需要的工夫才加载对应的页面,以分摊首页的加载压力,减少首页加载工夫

莫得效路由懒加载: 

import Home from '@/components/Home'  const router = new VueRouter({     routes: [      { path: '/home', component: Home }  ] }) 

用了路由懒加载: 

const router = new VueRouter({  routes: [    { path: '/home', component: () =>   import('@/components/Home') },    { path: '/login', component:   require('@/components/Home').default } ]  }) 

在参预这个路由的工夫才会走对应的 component,然后运行 import 编译加载组件,不错相识为 Promise 的 resolve 机制

 import:Es6语法步骤、编译时调用、是解构过程、不因循变量函数等  require:AMD步骤、运行时调用、是赋值过程,因循变量推测函数等

更多相关前端模块化的推行不错看我另一篇著作 前端模块化步骤详备回归

十. keep-alive缓存页面

比如在表单输入页面参预下一步后,再复返上一步到表单页时要保留表单输入的推行、比如在列表页>细目页>列表页,这么往返跳转的场景等

咱们都不错通过内置组件 <keep-alive></keep-alive> 来把组件缓存起来,在组件切换的工夫不进行卸载,这么当再次复返的工夫,就能从缓存中快速渲染,而不是再行渲染,以温和性能

只需要包裹想要缓存的组件即可 

<template>   <div id="app">     <keep-alive>       <router-view/>     </keep-alive>  </div>  </template
 也不错用 include/exclude 来 缓存/不缓存 指定组件  可通过两个人命周期 activated/deactivated 来获稳当前组件景色 十一. 事件的葬送

Vue 组件葬送时,会自动解绑它的沿途教导及事件监听器,但是仅限于组件本人的事件

而关于定时器、addEventListener 注册的监听器等,就需要在组件葬送的人命周期钩子中手动葬送或解绑,以幸免内存透露 

<script>  export default {     created() {       this.timer = setInterval(this.refresh, 2000)      addEventListener('touchmove',   this.touchmove, false)    },     beforeDestroy() {       clearInterval(this.timer)        this.timer = null        removeEventListener('touchmove',  this.touchmove, false)    } }  </script
十二. 图片懒加载

图片懒加载即是关于有好多图片的页面,为了提高页面加载速率,只加载可视区域内的图片,可视区域外的比及改换到可视区域后再去加载

这个功能一些 UI 框架都有自带的,如果莫得呢?

推选一个第三方插件 vue-lazyload 

npm i vue-lazyload -S  // main.js  import VueLazyload from 'vue-lazyload'  Vue.use(VueLazyload)  // 接着就不错在页面中使用 v-lazy 懒加载图片了  <img v-lazy="/static/images/1.png"> 

大要我方造轮子,手动封装一个自界说教导,这里封装好了一个兼容各浏览器的版块的,主如果判断浏览器支不因循 IntersectionObserver API,因循就用它竣事懒加载,不因循就用监听 scroll 事件+节流的相貌竣事 

const LazyLoad = {   // install设施   install(Vue, options) {    const defaultSrc = options.default    Vue.directive('lazy', {      bind(el, binding) {        LazyLoad.init(el, binding.value, defaultSrc)    },       inserted(el) {       if (IntersectionObserver) {          LazyLoad.observe(el)     } else {          LazyLoad.listenerScroll(el)        }    },  }) },   // 运行化   init(el, val, def) {  el.setAttribute('data-src', val)     el.setAttribute('src', def)  },   // 期骗IntersectionObserver监听el  observe(el) {     var io = new IntersectionObserver((entries) => {      const realSrc = el.dataset.src       if (entries[0].isIntersecting) {     if (realSrc) {         el.src = realSrc           el.removeAttribute('data-src')        }      }   })    io.observe(el)  },   // 监听scroll事件  listenerScroll(el) {     const handler =  LazyLoad.throttle(LazyLoad.load, 300)   LazyLoad.load(el)    window.addEventListener('scroll', () => {       handler(el)    })  },   // 加载竟然图片   load(el) {     const windowHeight =  document.documentElement.clientHeight   const elelTop = el.getBoundingClientRect().top     const elelBtm =   el.getBoundingClientRect().bottom    const realSrc = el.dataset.src     if (elTop - windowHeight < 0 && elBtm > 0) {    if (realSrc) {        el.src = realSrc         el.removeAttribute('data-src')      }    }  },   // 节流   throttle(fn, delay) {    let timer     let prevTime     return function (...args) {      const currTime = Date.now()     const context = this      if (!prevTime) prevTime = currTime      clearTimeout(timer)       if (currTime - prevTime > delay) {        prevTime = currTime           fn.apply(context, args)        clearTimeout(timer)         return      }     timer = setTimeout(function () {      prevTime = Date.now()      timer = null       fn.apply(context, args)    }, delay)   }  },  }  export default LazyLoad 

使用上是这么的,用 v-LazyLoad 代替 src 

<img v-LazyLoad="xxx.jpg" /> 
十三. SSR

这极少我在名堂中也莫得实践过,就不弄斧班门了