给我五分钟,我把 keep-alive 的用法和原理跟你说明白

keep-alive可以实现组件缓存,当组件切换时不会对当前组件进行卸载。

主要是有include、exclude、max三个属性;前两个属性允许keep-alive有条件的进行缓存;max可以定义组件最大的缓存个数,如果超过了这个个数的话,在下一个新实例创建之前,就会将以缓存组件中最久没有被访问到的实例销毁掉。

两个生命周期activated/deactivated,用来得知当前组件是否处于活跃状态。


Home.vue

<template><div class="hello"><h1>你怎么还在学习?🗑️</h1><input placeholder="输入框" /><router-link to="/about">我的人生理想</router-link></div>
</template> 

About.vue

<template><div class="hello"><h1>我想取老婆 🐜</h1></div>
</template> 

App.vue

<template><div id="app"><router-view/></div>
</template>

<script> import Home from './views/Home.vue'
import About from './views/About.vue'

export default {components: {Home,About,}
} </script> 

你在输入框中输入信息,点击跳转到另外一个页面后,回到该页面,你会发现,输入框中的文字消失了。怎么办勒

使用 keep-alive 包裹 router-view,同时指定需要缓存的组件名称。(PS:请在要缓存的组件中,写明 name 属性,并赋值。不然缓存不生效)

Home.vue

App.vue

<template><div id="app"><keep-alive include="Home"><router-view/></keep-alive></div>
</template>

<script> import Home from './views/Home.vue'
import About from './views/About.vue'

export default {components: {Home,About,}
} </script> 

结合 Router,缓存页面

router.js

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'

Vue.use(Router)

export default new Router({routes: [{path: '/',name: 'home',component: Home,// 需要被缓存meta: {keepAlive: true}},{path: '/about',name: 'about',component: () => import('./views/About.vue')},]
}) 

Home.vue

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

App.vue

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

<img src=“https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/199621f8f7074980be2f3f15aa99600d~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image) 剩下的一些其他特性,可以自行前往官网查阅 [cn.vuejs.org/v2/api/#kee…](https://link.juejin.cn/?target=https%3A%2F%2Fcn.vuejs.org%2Fv2%2Fapi%2F%23keep-alive “https://cn.vuejs.org/v2/api/#keep-alive”” style=“margin: auto” />

keep-alive 原理

keep-alive中运用了LRU(Least Recently Used)算法。

1.获取 keep-alive 包裹着的第一个子组件对象及其组件名; 如果 keep-alive 存在多个子元素,keep-alive 要求同时只有一个子元素被渲染。所以在开头会获取插槽内的子元素,调用 getFirstComponentChild 获取到第一个子元素的 VNode
2.根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。不匹配,直接返回组件实例(VNode),否则开启缓存策略。
3.根据组件ID和tag生成缓存Key,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该key在this.keys中的位置(更新key的位置是实现LRU置换策略的关键)。
4.如果不存在,则在this.cache对象中存储该组件实例并保存key值,之后检查缓存的实例数量是否超过max设置值,超过则根据LRU置换策略删除最近最久未使用的实例(即是下标为0的那个key)。最后将该组件实例的keepAlive属性值设置为true

var KeepAlive = {name: 'keep-alive',// 抽象组件abstract: true,// 接收的参数props: {include: patternTypes,exclude: patternTypes,max: [String, Number]},// 创建缓存表created: function created () {this.cache = Object.create(null);this.keys = [];},destroyed: function destroyed () {for (var key in this.cache) {pruneCacheEntry(this.cache, key, this.keys);}},mounted: function mounted () {var this$1 = this;this.$watch('include', function (val) {pruneCache(this$1, function (name) { return matches(val, name); });});this.$watch('exclude', function (val) {pruneCache(this$1, function (name) { return !matches(val, name); });});},render: function render () {var slot = this.$slots.default;// 获取 `keep-alive` 包裹着的第一个子组件对象及其组件名; // 如果 keep-alive 存在多个子元素,`keep-alive` 要求同时只有一个子元素被渲染。// 所以在开头会获取插槽内的子元素,// 调用 `getFirstComponentChild` 获取到第一个子元素的 `VNode`。var vnode = getFirstComponentChild(slot);var componentOptions = vnode && vnode.componentOptions;if (componentOptions) {// check patternvar name = getComponentName(componentOptions);var ref = this;var include = ref.include;var exclude = ref.exclude;// 根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。 if (// not included(include && (!name || !matches(include, name))) ||// excluded(exclude && name && matches(exclude, name))) {// 不匹配,直接返回组件实例(`VNode`),否则开启缓存策略。return vnode}var ref$1 = this;var cache = ref$1.cache;var keys = ref$1.keys;// 根据组件ID和tag生成缓存Keyvar key = vnode.key == null? componentOptions.Ctor.cid + (componentOptions.tag ? ("::" + (componentOptions.tag)) : ''): vnode.key;if (cache[key]) {// 并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值vnode.componentInstance = cache[key].componentInstance;// 并更新该key在this.keys中的位置(更新key的位置是实现LRU置换策略的关键)。remove(keys, key);keys.push(key);} else { // 如果不存在,则在this.cache对象中存储该组件实例并保存key值,cache[key] = vnode;keys.push(key);// 之后检查缓存的实例数量是否超过max设置值,超过则根据LRU置换策略删除最近最久未使用的实例if (this.max && keys.length > parseInt(this.max)) {pruneCacheEntry(cache, keys[0], keys, this._vnode);}}
		// 最后将该组件实例的keepAlive属性值设置为true。vnode.data.keepAlive = true;}return vnode || (slot && slot[0])}
}; 
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值