Keep-alive is a built-in component of vue.js. <keep-alive> when wrapping dynamic components, inactive component instances are cached rather than destroyed. It does not render a DOM element on its own, nor does it appear in the parent component chain. When a component is switched within <keep-alive>, its activated and deactivated lifecycle hook functions are executed accordingly. It provides include and exclude attributes that allow components to cache conditionally.
Take a chestnut
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if=! "" $route.meta.keepAlive"></router-view>
Copy the code
Switch button
When a button is clicked, the two inputs switch, but the state of the two input fields is cached, and the contents of the input tag do not disappear due to component switching.
* include - a string or regular expression. Only matching components are cached. * exclude - a string or regular expression. Any matching components will not be cached.Copy the code
<keep-alive include="a">
<component></component>
</keep-alive>
Copy the code
Caches only components whose name is A
<keep-alive exclude="a">
<component></component>
</keep-alive>
Copy the code
Everything is cached except the component whose name is A
Lifecycle hook
Keep-alive provides two life hooks, activated and deactivated.
Keep-alive stores the component in memory and does not destroy or recreate it. Therefore, the created method of the component is not called again. Instead, the activated and deactivated hooks are used to determine whether the component is active.
In-depth implementation of the Keep-alive component
The Created hook creates a cache object that can be used as a cache container to hold vNodes.
props: {
include: patternTypes,
exclude: patternTypes,
max: [String.Number]
},
created () {
// Create a cache object
this.cache = Object.create(null)
// Create a key alias array (component name)
this.keys = []
},
Copy the code
A Destroyed hook removes all component instances from the cache when the component is destroyed.
destroyed () {
/* Iterate over all cached component instances */
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
}
},
Copy the code
:::demo
render () {
/* Get the slot */
const slot = this.$slots.default
/* Get the first component */ according to the slot
const vnode: VNode = getFirstComponentChild(slot)
constcomponentOptions: ? VNodeComponentOptions = vnode && vnode.componentOptionsif (componentOptions) {
// Get component name (if component name is set, component label name is returned if not)
constname: ? string = getComponentName(componentOptions)// Destruct object assignment constants
const { include, exclude } = this
if ( /* Name is not in inlcude or is returned directly to vnode */ from exlude
// not included(include && (! name || ! matches(include, name))) ||// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, keys } = this
constkey: ? string = vnode.key ==null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? componentOptions.Ctor.cid + (componentOptions.tag ? ` : :${componentOptions.tag}` : ' ')
: vnode.key
if (cache[key]) { // Check whether the current cache exists. If yes, take the cache instance. If no, cache
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
// Check whether the maximum number of cache instances is set. If the maximum number of cache instances exceeds, delete the oldest data.
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
// Mark vnode with cache
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])}// Destroy the instance
function pruneCacheEntry (cache: VNodeCache, key: string, keys: Array
, current? : VNode
) {
const cached = cache[key]
if(cached && (! current || cached.tag ! == current.tag)) { cached.componentInstance.$destroy() } cache[key] =null
remove(keys, key)
}
/ / cache
function pruneCache (keepAliveInstance: any, filter: Function) {
const { cache, keys, _vnode } = keepAliveInstance
for (const key in cache) {
constcachedNode: ? VNode = cache[key]if (cachedNode) {
constname: ? string = getComponentName(cachedNode.componentOptions)// Component name does not match the filler condition. Destroy the instance and remove cahe
if(name && ! filter(name)) { pruneCacheEntry(cache, key, keys, _vnode) } } } }// Filter the filter function
function matches (pattern: string | RegExp | Array<string>, name: string) :boolean {
if (Array.isArray(pattern)) {
return pattern.indexOf(name) > - 1
} else if (typeof pattern === 'string') {
return pattern.split(', ').indexOf(name) > - 1
} else if (isRegExp(pattern)) {
return pattern.test(name)
}
/* istanbul ignore next */
return false
}
// Detect include and exclude data changes, write to cache or delete in real time
mounted () {
this.$watch('include', val => {
pruneCache(this, name => matches(val, name))
})
this.$watch('exclude', val => {
pruneCache(this, name => ! matches(val, name)) }) },Copy the code
: : :
By checking the Vue source code, it can be seen that keep-alive passes three attributes by default: include, exclude, Max, Max maximum cacheable length
Combined with source code we can implement a configurable cache router-view
<! --exclude - a string or regular expression. Any matching components will not be cached. -->
<! --TODO matches first by checking the component's own name option, and if the name option is not available, matching its local registered name -->
<keep-alive :exclude="keepAliveConf.value">
<router-view class="child-view" :key="$route.fullPath"></router-view>
</keep-alive>
<!-- 或者 -->
<keep-alive :include="keepAliveConf.value">
<router-view class="child-view" :key="$route.fullPath"></router-view>
</keep-alive>
<! -- Include or exclude depends on how many pages your project needs to cache -->
Copy the code
Create a keepaliveconf.js to place the component names to be matched
// Routing component named collection
var arr = ['component1'.'component2'];
export default {value: routeList.join()};
Copy the code
Configure the global method for resetting the cache
import keepAliveConf from 'keepAliveConf.js'
Vue.mixin({
methods: {
// Pass in the name of the component to be reset
resetKeepAive(name) {
const conf = keepAliveConf.value;
let arr = keepAliveConf.value.split(', ');
if (name && typeof name === 'string') {
let i = arr.indexOf(name);
if (i > - 1) {
arr.splice(i, 1);
keepAliveConf.value = arr.join();
setTimeout((a)= > {
keepAliveConf.value = conf
}, 500); }}},}})Copy the code