Understanding keep-alive

understand

definition:

It is a built-in component. When it wraps dynamic components, it will cache inactive component instances instead of destroying them.
keep-alive is an abstract component. It will not be rendered as a dom element, nor will it appear in the parent component chain

effect

If the component is in a cached state, prevent repeated dom rendering, reduce loading time and performance consumption, and improve user experience

principle

When the created function is called, save the VNode [virtual dom] node that needs to be cached in this.cache / when rendering (page rendering), if the name of the VNode meets the cache conditions (can be controlled by include and exclude), it will be from this Take out the previously cached VNode instance from .cache for rendering

use

parameter

parameter name value describe
include string or regular expression Only components with matching names will be cached
exclude string or regular expression Any component whose name matches will not be cached
max number How many component instances can be cached at most

Note: the include/exclude value is the name name in the component, not the routing component name name

// router.js
{
    
    
  path: '/home',
  name: 'home',
  component: () => import('../views/home.vue')
},
{
    
     
  path: '/about',
  name: 'about',
  component: () => import('../views/about.vue')
},

//首先声明只有两个页面分别是:home页面和about页面
// App.vue

//所有组件都要缓存【情况一】
<keep-alive>
   <router-view/>
</keep-alive>

//如果只缓存about内容【情况二】
<keep-alive include="about">
   <router-view/>
</keep-alive>

//如果不缓存about内容【情况三】
<keep-alive exclude="about">
   <router-view/>
</keep-alive>

----------------------------------------------------------------------------------------------------------------
补充: include/exclude 值的多种形式。

// 1. 将缓存 name 为 test 的组件(基本)
<keep-alive include='about'>
  <router-view/>
</keep-alive>
	
// 2. 将缓存 name 为 a 或者 b 的组件,结合动态组件使用
<keep-alive include='a,b'>
  <router-view/>
</keep-alive>
	
// 3. 使用正则表达式,需使用 v-bind
<keep-alive :include='/a|b/'>
  <router-view/>
</keep-alive>	
	
// 4.动态判断
<keep-alive :include='includedComponents'>
  <router-view/>
</keep-alive>
	
// 5. 将不缓存 name 为 test 的组件
<keep-alive exclude='home'>
  <router-view/>
</keep-alive>

// 6. 和 `<transition>` 一起使用
<transition>
  <keep-alive>
    <router-view/>
  </keep-alive>
</transition>

// 7. 数组 (使用 `v-bind`)
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>

// 关于页about.vue
<template>
  <div class="about">
    <h2>关于页</h2>
    <p @click="pClick">这是一个p标签</p>
  </div>
</template>
<script>
export default{
    
    
  name: 'AboutView',
  components: {
    
    

  },
  methods: {
    
    
    pClick(e) {
    
    
      console.log(e.target.style.color = 'red');
      console.log('p标签被点击了')
    }
  },
  created() {
    
    
    console.log('AboutView created')
  },
  destroyed() {
    
    
    console.log('AboutView destroyed')
  },
}
</script>
//首页home.vue
<template>
  <div class="home">
    <h2>首页</h2>
  </div>
</template>

<script>


export default {
    
    
  name: 'HomeView',
  components: {
    
    

  },
  created() {
    
    
    console.log('HomeView created')
  },
  destroyed() {
    
    
    console.log('HomeView destroyed')
  },
}
</script>

So at this time, if it is case 1, all components are cached.
If it is case 2, you can only see that the content in the p tag in the about component is cached, that is to say, when switching between home and about content, If the cache about
is in case three, then it is the cached home component

In addition, there is another way to cache
using the meta attribute in the route to control whether caching is required

Add the KeepAlive attribute to the meta in the about route to true, indicating that the current route needs to be cached

// router.js
{
    
    
  path: '/home',
  name: 'home',
  component: () => import('../views/home.vue')
},
{
    
     
  path: '/about',
  name: 'about',
  meta:{
    
    
    keepAlive:true
  },
  component: () => import('../views/about.vue')
},

The keep-alive code can be wrapped in combination with v-if, if the keepAlive in the meta is true, it will be cached, otherwise it will not be cached

<keep-alive>
  <router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" />

Then in actual development, we can starve and route guards to implement caching that requires caching components

export default {
    
    
  beforeRouteLeave(to, from, next) {
    
    
    to.meta.keepAlive = true;
    next();
  }
}
</script>

Then when using route cache, life cycle hook is bound to be used, so let's introduce the life cycle hook function related to it

name describe
actived Called when the keep-alive component is activated, this hook function is not called during server-side rendering
deactived Called when the keep-alive component is deactivated, the hook function is not called during server-side rendering

Explanation
The use will keep the data in the memory. If you want to get the latest data every time you enter the page, you need to get the data in the active phase, and undertake the task of getting the data in the original created hook
. Two lifecycle hooks: activated and deactivated

activated: called when the component is activated, it will also be called when the component is rendered for the first time, and then called every time keep-alive is activated deactivated
: called when the component is deactivated

Note:
These two life cycles will be called only when the component is wrapped by keep-alive. If it is used as a normal component, it will not be called. After version 2.1.0, after using exclude to exclude, even if it is wrapped in In keep-alive, these two hooks will still not be called! In addition, this hook will not be called when rendering on the server side

When to get the data?

When keep-alive is introduced, the page enters for the first time, the trigger sequence of hooks:
created==>mounted==》activated,
deactivated is triggered when exiting
, and activated is triggered when re-entering

We know that after keep-alive, the page template is initialized and parsed into HTML fragments for the first time, and the data in memory will not be re-parsed when it is entered again.
Use VirtualDOM for diff updates only when the data changes. Therefore, the data acquisition of page entry should also be placed in activated.
After the data is downloaded, the part of manually operating the DOM should also be executed in activated to take effect.

Therefore, you should leave a copy of the data acquisition code in activated, or directly transfer the code in created to activated without the created part

Practical application:
If the keep-alive component is not used, the page will be rendered honestly when the page rolls back, triggering the created hook, and the user experience is not good

The main usage scenarios are: there is a multi-level relationship in the menu [Homepage-"List Page-"Details Page]

When jumping to the list page from the homepage, the list page component re-renders;
when returning to the list page from the details page, the list component caches and does not re-request data

// app.vue
<template>
  <div id="app">
    <keep-alive :include="keepAliveInclude">
      <router-view/>
    </keep-alive>
  </div>
</template>

<script>
import {
    
     mapGetters } from 'vuex'
export default {
    
    
  name:'home',
  computed:{
    
    
    ...mapGetters([
      'keepAliveInclude',
    ])
  },
}
</script>

Save the state update of keepAliveInclude in the store

// store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    
    
  state: {
    
    
    // keepAlive缓存组件
    keepAliveInclude:[],
  },
  getters:{
    
    
    keepAliveInclude: state => state.keepAliveInclude,
  },
  mutations: {
    
    
    SET_KEEPALIVEINCLUDE:(state, keepAliveInclude) => {
    
    
      state.keepAliveInclude = keepAliveInclude;
    }
  },
  actions: {
    
    
    setKeepAliveInclude({
     
      commit }, keepAliveInclude){
    
    
      commit("SET_KEEPALIVEINCLUDE", keepAliveInclude)
    },
  },
})

List of pages that need to be cached.vue

<template>
  <div>
    <button @click="goHome">首页</button>
    <button @click="goDetail">详情</button>
    列表: <input type="text" v-model="inputVal">
  </div>
</template>

<script>
export default {
    
    
  name:'list',
  data(){
    
    
    return {
    
    
      inputVal:'',
    }
  },
  methods:{
    
    
    goDetail(){
    
    
      this.$router.push('./detail')
    },
    goHome(){
    
    
      this.$router.push('./home')
    }
  },
  beforeRouteLeave (to, from, next) {
    
    
    if(to.name == 'detail'){
    
    
      this.$store.dispatch('setKeepAliveInclude',['list'])
    }else{
    
    
      this.$store.dispatch('setKeepAliveInclude',[])
    }
    // next();
    setTimeout(() => {
    
     next(); }, 10); // next()需用定时器包裹,否则多次切换无法缓存
  }
}
</script>

Guess you like

Origin blog.csdn.net/Clover_zlx/article/details/130930807