五分鐘理解keep?alive用法及原理
引言
keep-alive
可以實現(xiàn)組件緩存,當(dāng)組件切換時不會對當(dāng)前組件進行卸載。
主要是有include、exclude、max
三個屬性;
前兩個屬性允許keep-alive
有條件的進行緩存;
max
可以定義組件最大的緩存?zhèn)€數(shù),如果超過了這個個數(shù)的話,在下一個新實例創(chuàng)建之前,就會將以緩存組件中最久沒有被訪問到的實例銷毀掉。
兩個生命周期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>
你在輸入框中輸入信息,點擊跳轉(zhuǎn)到另外一個頁面后,回到該頁面,你會發(fā)現(xiàn),輸入框中的文字消失了。怎么辦勒
使用 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>
結(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中運用了LRU(Least Recently Used)
算法。
- 獲取
keep-alive
包裹著的第一個子組件對象及其組件名; 如果 keep-alive 存在多個子元素,keep-alive
要求同時只有一個子元素被渲染。所以在開頭會獲取插槽內(nèi)的子元素,調(diào)用getFirstComponentChild
獲取到第一個子元素的VNode
。 - 根據(jù)設(shè)定的黑白名單(如果有)進行條件匹配,決定是否緩存。不匹配,直接返回組件實例(
VNode
),否則開啟緩存策略。 - 根據(jù)組件ID和tag生成緩存Key,并在緩存對象中查找是否已緩存過該組件實例。如果存在,直接取出緩存值并更新該key在
this.keys
中的位置(更新key的位置是實現(xiàn)LRU
置換策略的關(guān)鍵)。 - 如果不存在,則在
this.cache
對象中存儲該組件實例并保存key值,之后檢查緩存的實例數(shù)量是否超過max設(shè)置值,超過則根據(jù)LRU
置換策略刪除最近最久未使用的實例(即是下標(biāo)為0的那個key)。最后將該組件實例的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` 包裹著的第一個子組件對象及其組件名; // 如果 keep-alive 存在多個子元素,`keep-alive` 要求同時只有一個子元素被渲染。 // 所以在開頭會獲取插槽內(nèi)的子元素, // 調(diào)用 `getFirstComponentChild` 獲取到第一個子元素的 `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è)定的黑白名單(如果有)進行條件匹配,決定是否緩存。 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; // 根據(jù)組件ID和tag生成緩存Key var 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的位置是實現(xiàn)LRU置換策略的關(guān)鍵)。 remove(keys, key); keys.push(key); } else { // 如果不存在,則在this.cache對象中存儲該組件實例并保存key值, cache[key] = vnode; keys.push(key); // 之后檢查緩存的實例數(shù)量是否超過max設(shè)置值,超過則根據(jù)LRU置換策略刪除最近最久未使用的實例 if (this.max && keys.length > parseInt(this.max)) { pruneCacheEntry(cache, keys[0], keys, this._vnode); } } // 最后將該組件實例的keepAlive屬性值設(shè)置為true。 vnode.data.keepAlive = true; } return vnode || (slot && slot[0]) } };
以上就是五分鐘理解keep alive用法及原理的詳細內(nèi)容,更多關(guān)于keep alive用法原理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue.js el-tooltip根據(jù)文字長度控制是否提示toolTip問題
這篇文章主要介紹了vue.js el-tooltip根據(jù)文字長度控制是否提示toolTip問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02vue實現(xiàn)標(biāo)簽頁切換/制作tab組件詳細教程
在項目開發(fā)中需要使用vue實現(xiàn)tab頁簽切換功能,所以這里總結(jié)下,這篇文章主要給大家介紹了關(guān)于vue實現(xiàn)標(biāo)簽頁切換/制作tab組件的相關(guān)資料,需要的朋友可以參考下2023-11-11詳解為什么Vue中不要用index作為key(diff算法)
這篇文章主要介紹了詳解為什么Vue中不要用index作為key(diff算法),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04Vue.js做select下拉列表的實例(ul-li標(biāo)簽仿select標(biāo)簽)
下面小編就為大家分享一篇Vue.js做select下拉列表的實例(ul-li標(biāo)簽仿select標(biāo)簽),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03vue項目中頁面底部出現(xiàn)白邊及空白區(qū)域錯誤的問題
這篇文章主要介紹了vue項目中頁面底部出現(xiàn)白邊及空白區(qū)域錯誤的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08