五分鐘理解keep?alive用法及原理
引言
keep-alive可以實(shí)現(xiàn)組件緩存,當(dāng)組件切換時(shí)不會(huì)對(duì)當(dāng)前組件進(jìn)行卸載。
主要是有include、exclude、max三個(gè)屬性;
前兩個(gè)屬性允許keep-alive有條件的進(jìn)行緩存;
max可以定義組件最大的緩存?zhèn)€數(shù),如果超過了這個(gè)個(gè)數(shù)的話,在下一個(gè)新實(shí)例創(chuàng)建之前,就會(huì)將以緩存組件中最久沒有被訪問到的實(shí)例銷毀掉。
兩個(gè)生命周期activated/deactivated,用來得知當(dāng)前組件是否處于活躍狀態(tài)。
Home.vue
<template>
<div class="hello">
<h1>你怎么還在學(xué)習(xí)????</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>
你在輸入框中輸入信息,點(diǎn)擊跳轉(zhuǎn)到另外一個(gè)頁面后,回到該頁面,你會(huì)發(fā)現(xiàn),輸入框中的文字消失了。怎么辦勒

使用 keep-alive 包裹 router-view,同時(shí)指定需要緩存的組件名稱。(PS:請(qǐng)?jiān)谝彺娴慕M件中,寫明 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>

結(jié)合 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>

剩下的一些其他特性,可以自行前往官網(wǎng)查閱 cn.vuejs.org/v2/api/#kee…
keep-alive 原理
keep-alive中運(yùn)用了LRU(Least Recently Used)算法。
- 獲取
keep-alive包裹著的第一個(gè)子組件對(duì)象及其組件名; 如果 keep-alive 存在多個(gè)子元素,keep-alive要求同時(shí)只有一個(gè)子元素被渲染。所以在開頭會(huì)獲取插槽內(nèi)的子元素,調(diào)用getFirstComponentChild獲取到第一個(gè)子元素的VNode。 - 根據(jù)設(shè)定的黑白名單(如果有)進(jìn)行條件匹配,決定是否緩存。不匹配,直接返回組件實(shí)例(
VNode),否則開啟緩存策略。 - 根據(jù)組件ID和tag生成緩存Key,并在緩存對(duì)象中查找是否已緩存過該組件實(shí)例。如果存在,直接取出緩存值并更新該key在
this.keys中的位置(更新key的位置是實(shí)現(xiàn)LRU置換策略的關(guān)鍵)。 - 如果不存在,則在
this.cache對(duì)象中存儲(chǔ)該組件實(shí)例并保存key值,之后檢查緩存的實(shí)例數(shù)量是否超過max設(shè)置值,超過則根據(jù)LRU置換策略刪除最近最久未使用的實(shí)例(即是下標(biāo)為0的那個(gè)key)。最后將該組件實(shí)例的keepAlive屬性值設(shè)置為true。
var KeepAlive = {
name: 'keep-alive',
// 抽象組件
abstract: true,
// 接收的參數(shù)
props: {
include: patternTypes,
exclude: patternTypes,
max: [String, Number]
},
// 創(chuàng)建緩存表
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` 包裹著的第一個(gè)子組件對(duì)象及其組件名;
// 如果 keep-alive 存在多個(gè)子元素,`keep-alive` 要求同時(shí)只有一個(gè)子元素被渲染。
// 所以在開頭會(huì)獲取插槽內(nèi)的子元素,
// 調(diào)用 `getFirstComponentChild` 獲取到第一個(gè)子元素的 `VNode`。
var vnode = getFirstComponentChild(slot);
var componentOptions = vnode && vnode.componentOptions;
if (componentOptions) {
// check pattern
var name = getComponentName(componentOptions);
var ref = this;
var include = ref.include;
var exclude = ref.exclude;
// 根據(jù)設(shè)定的黑白名單(如果有)進(jìn)行條件匹配,決定是否緩存。
if (
// not included
(include && (!name || !matches(include, name))) ||
// excluded
(exclude && name && matches(exclude, name))
) {
// 不匹配,直接返回組件實(shí)例(`VNode`),否則開啟緩存策略。
return vnode
}
var ref$1 = this;
var cache = ref$1.cache;
var keys = ref$1.keys;
// 根據(jù)組件ID和tag生成緩存Key
var key = vnode.key == null
? componentOptions.Ctor.cid + (componentOptions.tag ? ("::" + (componentOptions.tag)) : '')
: vnode.key;
if (cache[key]) {
// 并在緩存對(duì)象中查找是否已緩存過該組件實(shí)例。如果存在,直接取出緩存值
vnode.componentInstance = cache[key].componentInstance;
// 并更新該key在this.keys中的位置(更新key的位置是實(shí)現(xiàn)LRU置換策略的關(guān)鍵)。
remove(keys, key);
keys.push(key);
} else {
// 如果不存在,則在this.cache對(duì)象中存儲(chǔ)該組件實(shí)例并保存key值,
cache[key] = vnode;
keys.push(key);
// 之后檢查緩存的實(shí)例數(shù)量是否超過max設(shè)置值,超過則根據(jù)LRU置換策略刪除最近最久未使用的實(shí)例
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode);
}
}
// 最后將該組件實(shí)例的keepAlive屬性值設(shè)置為true。
vnode.data.keepAlive = true;
}
return vnode || (slot && slot[0])
}
};以上就是五分鐘理解keep alive用法及原理的詳細(xì)內(nèi)容,更多關(guān)于keep alive用法原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
@vue/cli4升級(jí)@vue/cli5?node.js?polyfills錯(cuò)誤的解決方式
最近在升級(jí)vue/cli的具有了一些問題,解決問題的過程也花費(fèi)了些時(shí)間,所以下面這篇文章主要給大家介紹了關(guān)于@vue/cli4升級(jí)@vue/cli5?node.js?polyfills錯(cuò)誤的解決方式,需要的朋友可以參考下2022-09-09
React組件通信之路由傳參(react-router-dom)
本文主要介紹了React組件通信之路由傳參(react-router-dom),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
vue中如何實(shí)現(xiàn)復(fù)制內(nèi)容到剪切板詳解
有些業(yè)務(wù)需求需要點(diǎn)擊按鈕復(fù)制鏈接,下面這篇文章主要給大家介紹了關(guān)于vue中如何實(shí)現(xiàn)復(fù)制內(nèi)容到剪切板的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10
深入探索VueJS Scoped CSS 實(shí)現(xiàn)原理
這篇文章主要介紹了深入探索VueJS Scoped CSS 實(shí)現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Vue中使用Echarts響應(yīng)式布局flexible.js+rem適配方案詳解
這篇文章主要介紹了Vue中使用Echarts響應(yīng)式布局flexible.js+rem適配方案詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-01-01
vue3+elementPlus?table中添加輸入框并提交校驗(yàn)
這篇文章主要介紹了vue3+elementPlus?table里添加輸入框并提交校驗(yàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08

