Some optimizations for vue projects


foreword

Mainly record some optimizations of the vue project


1. Rendering optimization

v-for

Avoid using v-if and v-for at the same level, v-for has a higher priority than v-if, which will cause data rendering errors

v-for sets the value of the key, try not to use the index, and use the unique identifier in the data, which is conducive to the location and diff of the dom.


Choice of v-show and v-if

Frequently reused components are rendered with v-show (v-show is hidden and not destroyed).
On the contrary, use v-if (directly determine whether to create)


Long List Optimization

Purely for data display, no hot update required

The data in data will be monitored, and the data will change when it changes,
so the object.freeze (data) method is used to freeze the data.

long list

Use virtual scrolling to only render the content of a small area
and only render the data of the viewport, that is to say, the number of rendered DOM nodes is fixed

page:

<template>
  <div>
    <div>
      <span v-if="list.length===0">暂无数据!!!</span>
      <div v-else class="box" :style="`height:${viewH}px;overflow-y:scroll;`" @scroll="handleScroll">
        <ul>
          <li :style="`transform:translateY(${offsetY}px); height:${itemH}px;`" v-for='i in clist' :key="i">{
   
   { i }}</li>
        </ul>
      </div>
    </div>
    <button @click="gotoCSSLongList" class="but">CssLongList</button>
  </div>
</template>

logic:

<script>
export default {
    
    
  name: "LongListOne",
  data() {
    
    
    return {
    
    
      list: [],//上万条总数据
      clist: [],// 页面展示数据
      viewH: 500, // 可视box高度
      itemH: 60, // 单项高度
      scrollH: '', // 整个滚动列表高度
      showNum: '',//可视化高度一次能装几个列表
      offsetY: 0// 动态偏移量
    }
  },
  mounted() {
    
    
    for (let index = 0; index < 100000; index++) {
    
    // 10万条数据
      this.list.push(index)
    }
    this.scrollH = this.list.length * this.itemH;// 计算总高度
    // 计算可视化高度一次能装几个列表, 多设置几个防止滚动时候直接替换
    this.showNum = Math.floor(this.viewH / this.itemH) + 4
    // 默认展示几个
    this.clist = this.list.slice(0, this.showNum);
    this.lastTime = new Date().getTime()
  },
  computed: {
    
    },
  methods: {
    
    
    // 滚动监视器
    handleScroll(e) {
    
    
      let {
    
    lastTime,itemH,list}=this
      if (new Date().getTime() - lastTime > 10) {
    
    
        let scrollTop = e.target.scrollTop // 滚去的高度
        // 每一次滚动后根据scrollTop值获取一个可以整除itemH结果进行偏移
        // 例如: 滚动的scrllTop = 1220  1220 % this.itemH = 20  offsetY = 1200
        this.offsetY = scrollTop - (scrollTop % itemH)
        //上面卷掉了多少,就要往下平移多少,不然showNum滚出可视区外了
        this.clist = list.slice(
          Math.floor(scrollTop / itemH),  // 计算卷入了多少条
          Math.floor(scrollTop / itemH) + this.showNum
        )
        this.lastTime = new Date().getTime()
      }
    },

    // 跳转
    gotoCSSLongList(){
    
    
      this.$router.replace('/CssLongList')
    }
  }
}
</script>

style:

<style scoped>
* {
    
    
  padding: 0;
  margin: 0;
  list-style: none;
  box-sizing: border-box;
}
li {
    
    
  text-align: center;
  line-height: 60px;
  border-bottom: 1px solid red;
}
.but{
    
    
  height: 40px;
  width: 100px;
  margin-top: 10%;
}
</style>

plug-in

vue-virtual-scroller或者vue-virtual-scroll-list

Self-encapsulation

1. The data is given to:

  • Elements listen to scroll events (scroll events)
  • Calculating the height of the visualization can hold several lists at a time, and then perform slice interception from the total data
  • After each scroll, obtain a result that can be divisible by itemH according to the scrollTop value for offset (scrollTop: the distance that the scroll bar moves)

2. Data pass request:

代码实现存在点问题修改后再上传


event destruction

When a Vue component is destroyed, it will automatically unbind all its command events and listeners, but only limited to the component itself.
For example, timers are best destroyed manually during the destruction phase to avoid memory leaks

created(){
    
    
  this.timer = setInterval(this.refresh,)
}

beforeDestroy(){
    
    
  clearInterval(this.timer)
}

Stateless components are marked as functional components (static components)

It only receives the value passed by the parent component, does not process it by itself, has no state, and does not create an instance.

Function components do not have this

<template functional> // 函数组件
 <div class="cell">
    <div v-if="props.value" class="on"></div>
    <section v-else class="off"></section>
 <div>
</template >
<script>
 export default {
    
    
  props: ['value']
}
</script>

subcomponent split

The time-consuming tasks in the subcomponents are handed over to the components themselves for management, without affecting the loading of the overall page

<template>
 <div>
   <HelloWorld/>
 </div>
</template>
<script>
export default {
    
    
  // 子组件自己管自己
  HelloWorld:{
    
    
    methods:{
    
    
      heavy(){
    
    /* 耗时任务 */}
    },
    render(h) {
    
    
      return h('div', this.heavy());
    }
  }
}

variable localization

Reduce the use of this.data to obtain data and reduce unnecessary processing.
Use a variable to obtain data first, and process the data on this variable.

When using this. data, there will be data hijacking, and it will waste time to call get/set for processing.


Modularization and componentization

  • Encapsulating highly multiplexable modules
  • Split highly reusable components
  • Component configurability
<template>
// 可配置
 <button
   :class="['mybtn',`btn-${btnStyle}`]"
   @click="myBtnClick($event)"
   v-show="btnShow"
 >
   <slot></slot>
 </button>
</template>
<script>

export default {
      
      
  name: 'MyBtn',
  props: {
      
      
    btnStyle: String,
    btnShow: Boolean
  },
  setup (props,ctx){
      
      
    const myBtnClick = (e)=>{
      
      
      ctx.emit('my-btn-click', e);
    }
    return{
      
      
      myBtnClick
    }
  }
}
</script>

<style lang="scss" scoped>
.mybtn {
      
      
  border: none;
  outline: none;
  height:34px;
  padding: 0 15px;
  background-color: #fff;
  border: 1px solid #fff;
}
&.btn-default{
      
      
  color: #333;
  background-color: #fff;
  border-color: #ccc;
}
&.btn-primary{
      
      
  color: #fff;
  background-color: #317DEF;
  border-color: #317DEF;
}
</style>

Two, lazy loading

Routing lazy loading

const router = new VueRouter({
    
    
  routes:[
    {
    
    path:'.foo', component: () =>import('./Foo.vue')}
 ]
})

Image lazy loading

use plug-ins

vue-lazyload

<img v-lazy="图片地址">

Self-encapsulation

代码完善后上传


Three, keep-alive cache page

principle

When the created periodic function (after init initialization) is called. Save the VNode node that needs to be cached in this.cache, when calling the render function before rendering the page. If VNodename meets the cache conditions (controlled by include and exclude), the cached VNode instance will be taken from this.cache for rendering.

parameter

  • include: character or regular expression. Components with matching names will be rendered.
  • exclude: character or regular expression. Components with matching names will not be rendered.
  • max: number. The maximum number of instances that can be cached.

Periodic function when wrapped by keep-alive

activated

  • Called when the keep-alive component is activated
  • Server side rendering is not being invoked

deactivated

  • Called when the keep-alive component is deactivated
  • Not called during server rendering

Notice

  • keep-alive will keep the data in memory. If you want to get the latest data, you need to get it in the activated hook function.
  • The name required by include is the name of the component
  • When nesting sibling pages in multiple levels, when caching one of the pages, the parent level will be cached, causing all child pages to be cached. In this case, other sibling pages need to be manually destroyed.
<keep-alive>    
<router-view v-if="$route.meta.keepAlive"></router-view></keep-alive>
// 销毁不需要的兄弟组件
<router-view v-if="!$route.meta.keepAlive"></router-view>

scenes to be used

If it is necessary to switch between different components, a certain component needs not to change.
For example: after inputting text in the search box, when switching components, the text in the input box will not disappear, nor will it disappear when returning.

Instructions

Using the attributes include and exclude

// 只缓存名字为home的组件
<keep-alive include="home">
   <router-view />
</keep-alive>
// 缓存整个组件
<keep-alive>
   <router-view />
</keep-alive>

The meta attribute in the route to control the cache

// meta属性中keepAlive值设为true
{
    
    
      path: '/',
      name: 'home',
      meta:{
    
    
        keepAlive:true
      },
      component: Home
    }
// 配合 keep-alive进行控制缓存
<keep-alive>
      <router-view v-if="$route.meta.keepAlive" />
</keep-alive>

existing problems

After the component is cached, there is no destruction phase. When the component is switched, life cycle functions such as created will not be called, resulting in data not being updated in time.

Solution:

Use the provided activated and deactivated functions to get whether the current component is active.
Get data and update data in the activated function (cached components will have these two functions)

4. Packaging optimization

1. Import library

Introduce on demand to avoid excessive volume

import {
    
    Button , selet}from 'element-ui';

2. Introduce resources

Plug-in cdn, image cdn, use CSS icons
to reduce project size


3. Packaging configuration

Location: build/config/index.js
Property: productionGzip: true
Function: Packaging and compression

Location: true build/config/index.js
Attribute: productionSourceMap: false
Function: Reduce the packaging volume Locating the source code will generate a map file that may cause source code leakage


5. First screen optimization

Data loading uses the loding skeleton screen

Wiping the skeleton screen during the data loading phase can bring a better user experience


The first screen uses SSR server-side rendering

  • Client sends request to server
  • The server reads the template, parses it into dom nodes, and returns a complete HTML structure of the first screen
  • The client activates the first screen (activate the interactive code written by the user on the front end and turn it into a spa application again)
  • In this way, when the user clicks on the hyperlink and jumps again, they will no longer send requests to the server, but use the front-end routing to jump, and only send some ajax request data

use web workers

effect

Let JS implement multithreading

Create a multi-threaded running environment for JS, allowing the main thread to create worker threads and assign tasks to the latter. While the main thread is running, the worker threads are also running without interfering with each other. After the worker threads run, the results are returned to the main thread.

This does not mean that the JS language itself supports multi-threading capabilities, but that the browser as the host environment provides a multi-threaded running environment for JS.

use

Worker() constructor, the first parameter is the URL of the script (must comply with the same-origin policy), this parameter is required, and only JS scripts can be loaded, otherwise an error will be reported. The second parameter is a configuration object, which is optional. One of its functions is to specify the name of the Worker to distinguish multiple Worker threads.

var myWorker = new Worker(jsUrl, options)

scenes to be used

  1. Some encryption and decryption algorithms for encrypted data
    are more complicated, or when encrypting and decrypting a lot of data, it will consume a lot of computing resources and cause the UI thread to become unresponsive. Therefore, this is a good time to use Web Worker. A seamless operation UI.

  2. Prefetch data
    Sometimes in order to improve the data loading speed, you can use the Worker thread to obtain data in advance, because the Worker thread can use XMLHttpRequest.

  3. Pre-rendering
    In some rendering scenarios, such as rendering a complex canvas, effects such as reflection, refraction, light and shadow, materials, etc. need to be calculated. The logic of these calculations can be executed using Worker threads, or multiple Worker threads can be used. Here There is an example of ray tracing.

  4. Complex data processing scenarios
    Some retrieval, sorting, filtering, and analysis are time-consuming. In this case, Web Worker can be used instead of occupying the main thread.

  5. Preloading pictures
    Sometimes a page has many pictures, or when there are several large pictures, if business constraints do not consider lazy loading, you can also use Web Worker to load pictures. You can refer to the exploration in this article, which is simple here Summarize.


Optimize webpack configuration

  • Webpack's code-split combined with vue-router for lazy loading
  • webpack's conthash mode caches file level changes

Summarize

The above records the optimization of vue in various aspects, and the optimization of webpackp is perfected after learning webpackp

Guess you like

Origin blog.csdn.net/smznbhh/article/details/126928382