取消网站备案流程,国内国际新闻最新消息10条,如何做好品牌宣传工作,广州网页模板建站一、Keep-alive 是什么
keep-alive是vue中的内置组件#xff0c;能在组件切换过程中将状态保留在内存中#xff0c;防止重复渲染DOM
keep-alive 包裹动态组件时#xff0c;会缓存不活动的组件实例#xff0c;而不是销毁它们
keep-alive可以设置以下props属性#xff1a… 一、Keep-alive 是什么
keep-alive是vue中的内置组件能在组件切换过程中将状态保留在内存中防止重复渲染DOM
keep-alive 包裹动态组件时会缓存不活动的组件实例而不是销毁它们
keep-alive可以设置以下props属性
include - 字符串或正则表达式。只有名称匹配的组件会被缓存exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存max - 数字。最多可以缓存多少组件实例
关于keep-alive的基本用法
keep-alivecomponent :isview/component
/keep-alive
使用includes和exclude
keep-alive includea,bcomponent :isview/component
/keep-alive!-- 正则表达式 (使用 v-bind) --
keep-alive :include/a|b/component :isview/component
/keep-alive!-- 数组 (使用 v-bind) --
keep-alive :include[a, b]component :isview/component
/keep-alive匹配首先检查组件自身的 name 选项如果 name 选项不可用则匹配它的局部注册名称 (父组件 components 选项的键值)匿名组件不能被匹配
设置了 keep-alive 缓存的组件会多出两个生命周期钩子activated与deactivated
首次进入组件时beforeRouteEnter beforeCreate created mounted activated … … beforeRouteLeave deactivatedbeforeRouteEnter activated … … beforeRouteLeave deactivated
二、使用场景
使用原则当我们在某些场景下不需要让页面重新加载时我们可以使用keepalive
举个栗子:
当我们从首页–列表页–商详页–再返回这时候列表页应该是需要keep-alive
从首页–列表页–商详页–返回到列表页(需要缓存)–返回到首页(需要缓存)–再次进入列表页(不需要缓存)这时候可以按需来控制页面的keep-alive
在路由中设置keepAlive属性判断是否需要缓存
{path: list,name: itemList, // 列表页component (resolve) {require([/pages/item/list], resolve)},meta: {keepAlive: true,title: 列表页}
}使用
div idapp classwrapperkeep-alive!-- 需要缓存的视图组件 -- router-view v-if$route.meta.keepAlive/router-view/keep-alive!-- 不需要缓存的视图组件 --router-view v-if!$route.meta.keepAlive/router-view
/div三、原理分析
keep-alive是vue中内置的一个组件
源码位置src/core/components/keep-alive.js
export default {name: keep-alive,abstract: true,props: {include: [String, RegExp, Array],exclude: [String, RegExp, Array],max: [String, Number]},created () {this.cache Object.create(null)this.keys []},destroyed () {for (const key in this.cache) {pruneCacheEntry(this.cache, key, this.keys)}},mounted () {this.$watch(include, val {pruneCache(this, name matches(val, name))})this.$watch(exclude, val {pruneCache(this, name !matches(val, name))})},render() {/* 获取默认插槽中的第一个组件节点 */const slot this.$slots.defaultconst vnode getFirstComponentChild(slot)/* 获取该组件节点的componentOptions */const componentOptions vnode vnode.componentOptionsif (componentOptions) {/* 获取该组件节点的名称优先获取组件的name字段如果name不存在则获取组件的tag */const name getComponentName(componentOptions)const { include, exclude } this/* 如果name不在inlcude中或者存在于exlude中则表示不缓存直接返回vnode */if ((include (!name || !matches(include, name))) ||// excluded(exclude name matches(exclude, name))) {return vnode}const { cache, keys } this/* 获取组件的key值 */const key 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/* 拿到key值后去this.cache对象中去寻找是否有该值如果有则表示该组件有缓存即命中缓存 */if (cache[key]) {vnode.componentInstance cache[key].componentInstance// make current key freshestremove(keys, key)keys.push(key)}/* 如果没有命中缓存则将其设置进缓存 */else {cache[key] vnodekeys.push(key)// prune oldest entry/* 如果配置了max并且缓存的长度超过了this.max则从缓存中删除第一个 */if (this.max keys.length parseInt(this.max)) {pruneCacheEntry(cache, keys[0], keys, this._vnode)}}vnode.data.keepAlive true}return vnode || (slot slot[0])}
}可以看到该组件没有template而是用了render在组件渲染的时候会自动执行render函数
this.cache是一个对象用来存储需要缓存的组件它将以如下形式存储
this.cache {key1:组件1,key2:组件2,// ...
}在组件销毁的时候执行pruneCacheEntry函数
function pruneCacheEntry (cache: VNodeCache,key: string,keys: Arraystring,current?: VNode
) {const cached cache[key]/* 判断当前没有处于被渲染状态的组件将其销毁*/if (cached (!current || cached.tag ! current.tag)) {cached.componentInstance.$destroy()}cache[key] nullremove(keys, key)
}在mounted钩子函数中观测 include 和 exclude 的变化如下
mounted () {this.$watch(include, val {pruneCache(this, name matches(val, name))})this.$watch(exclude, val {pruneCache(this, name !matches(val, name))})
}如果include 或exclude 发生了变化即表示定义需要缓存的组件的规则或者不需要缓存的组件的规则发生了变化那么就执行pruneCache函数函数如下
function pruneCache (keepAliveInstance, filter) {const { cache, keys, _vnode } keepAliveInstancefor (const key in cache) {const cachedNode cache[key]if (cachedNode) {const name getComponentName(cachedNode.componentOptions)if (name !filter(name)) {pruneCacheEntry(cache, key, keys, _vnode)}}}
}在该函数内对this.cache对象进行遍历取出每一项的name值用其与新的缓存规则进行匹配如果匹配不上则表示在新的缓存规则下该组件已经不需要被缓存则调用pruneCacheEntry函数将其从this.cache对象剔除即可
关于keep-alive的最强大缓存功能是在render函数中实现
首先获取组件的key值
const key vnode.key null?
componentOptions.Ctor.cid (componentOptions.tag ? ::${componentOptions.tag} : )
: vnode.key拿到key值后去this.cache对象中去寻找是否有该值如果有则表示该组件有缓存即命中缓存如下
/* 如果命中缓存则直接从缓存中拿 vnode 的组件实例 */
if (cache[key]) {vnode.componentInstance cache[key].componentInstance/* 调整该组件key的顺序将其从原来的地方删掉并重新放在最后一个 */remove(keys, key)keys.push(key)
} 直接从缓存中拿 vnode 的组件实例此时重新调整该组件key的顺序将其从原来的地方删掉并重新放在this.keys中最后一个
this.cache对象中没有该key值的情况如下
/* 如果没有命中缓存则将其设置进缓存 */
else {cache[key] vnodekeys.push(key)/* 如果配置了max并且缓存的长度超过了this.max则从缓存中删除第一个 */if (this.max keys.length parseInt(this.max)) {pruneCacheEntry(cache, keys[0], keys, this._vnode)}
}表明该组件还没有被缓存过则以该组件的key为键组件vnode为值将其存入this.cache中并且把key存入this.keys中
此时再判断this.keys中缓存组件的数量是否超过了设置的最大缓存数量值this.max如果超过了则把第一个缓存组件删掉
四、思考题缓存后如何获取数据
解决方案可以有以下两种
beforeRouteEnteractived
beforeRouteEnter
每次组件渲染的时候都会执行beforeRouteEnter
beforeRouteEnter(to, from, next){next(vm{console.log(vm)// 每次进入路由执行vm.getData() // 获取数据})
},actived
在keep-alive缓存的组件被激活的时候都会执行actived钩子
activated(){this.getData() // 获取数据
},注意服务器端渲染期间avtived不被调用