Maison > Article > interface Web > Parlons de la compréhension du composant intégré keep-alive de Vue
Qu'est-ce que Keep-alive ? L'article suivant parlera de votre compréhension du composant intégré vue keep-alive. J'espère qu'il vous sera utile !
keep-alive
est un composant intégré dans vue
, qui peut conserver l'état lors du changement de composant . En mémoire, empêche le rendu répété du DOM
. [Recommandations associées : tutoriel vidéo vuejskeep-alive
是vue
中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM
。【相关推荐:vuejs视频教程、web前端开发】
keep-alive
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
keep-alive
可以设置以下props
属性:
include
- 字符串或正则表达式。只有名称匹配的组件会被缓存exclude
- 字符串或正则表达式。任何名称匹配的组件都不会被缓存max
- 数字。最多可以缓存多少组件实例关于keep-alive
的基本用法:
<keep-alive> <component :is="view"></component> </keep-alive>
使用includes
和exclude
:
<keep-alive include="a,b"> <component :is="view"></component> </keep-alive> <!-- 正则表达式 (使用 `v-bind`) --> <keep-alive :include="/a|b/"> <component :is="view"></component> </keep-alive> <!-- 数组 (使用 `v-bind`) --> <keep-alive :include="['a', 'b']"> <component :is="view"></component> </keep-alive>
匹配首先检查组件自身的 name
选项,如果 name
选项不可用,则匹配它的局部注册名称 (父组件 components
选项的键值),匿名组件不能被匹配
设置了 keep-alive 缓存的组件,会多出两个生命周期钩子(activated
与deactivated
):
beforeRouteEnter
> beforeCreate
> created
> mounted
> activated
> ... ... > beforeRouteLeave
> deactivated
beforeRouteEnter
>activated
> ... ... > beforeRouteLeave
> deactivated
使用原则:当我们在某些场景下不需要让页面重新加载时我们可以使用keepalive
举个栗子:
当我们从首页
–>列表页
–>商详页
–>再返回
,这时候列表页应该是需要keep-alive
从首页
–>列表页
–>商详页
–>返回到列表页(需要缓存)
–>返回到首页(需要缓存)
–>再次进入列表页(不需要缓存)
,这时候可以按需来控制页面的keep-alive
在路由中设置keepAlive
属性判断是否需要缓存
{ path: 'list', name: 'itemList', // 列表页 component (resolve) { require(['@/pages/item/list'], resolve) }, meta: { keepAlive: true, title: '列表页' } }
使用7c9485ff8c3cba5ae9343ed63c2dc3f7
<div id="app" class='wrapper'> <keep-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.default const vnode = getFirstComponentChild(slot) /* 获取该组件节点的componentOptions */ const componentOptions = vnode && vnode.componentOptions if (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 freshest remove(keys, key) keys.push(key) } /* 如果没有命中缓存,则将其设置进缓存 */ else { cache[key] = vnode keys.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: Array<string>, current?: VNode ) { const cached = cache[key] /* 判断当前没有处于被渲染状态的组件,将其销毁*/ if (cached && (!current || cached.tag !== current.tag)) { cached.componentInstance.$destroy() } cache[key] = null remove(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 } = keepAliveInstance for (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
, développement web front-end
keep-alive
Lors de l'encapsulation des composants dynamiques, le cache seront des instances de composants inactives au lieu de les détruire. 🎜🎜keep-alive
peut définir les propriétés props
suivantes : 🎜include
- chaîne ou expression régulière. Seuls les composants dont les noms correspondent seront mis en cache.exclure
- Chaîne ou expression régulière. Tout composant avec un nom correspondant ne sera pas mis en cachemax
- nombre. Le nombre maximum d'instances de composants pouvant être mises en cachekeep-alive
: 🎜/* 如果命中缓存,则直接从缓存中拿 vnode 的组件实例 */ if (cache[key]) { vnode.componentInstance = cache[key].componentInstance /* 调整该组件key的顺序,将其从原来的地方删掉并重新放在最后一个 */ remove(keys, key) keys.push(key) }🎜Utilisez
includes
et exclude
: 🎜/* 如果没有命中缓存,则将其设置进缓存 */ else { cache[key] = vnode keys.push(key) /* 如果配置了max并且缓存的长度超过了this.max,则从缓存中删除第一个 */ if (this.max && keys.length > parseInt(this.max)) { pruneCacheEntry(cache, keys[0], keys, this._vnode) } }🎜La correspondance vérifie d'abord l'option
name
du composant lui-même. Si l'option name
n'est pas disponible, elle correspond ensuite à son nom d'enregistrement local (parent). valeur de la clé d'option du composant components code>), les composants anonymes ne peuvent pas être mis en correspondance 🎜🎜Les composants avec un cache keep-alive configuré auront deux hooks de cycle de vie supplémentaires (<code>activé
et désactivé
): 🎜beforeRouteEnter
> beforeCreate
> > monté code> > <code>activé
> ... ... > li>beforeRouteEnter
>activé
> ... ... > code>désactivékeepalive
🎜🎜Par exemple :🎜🎜Quand nous passons de la Page d'accueil
–>Page de liste
–>Page de détails sur l'entreprise
–> ;Retour
À ce stade, la page de liste doit être maintenue en vie
🎜🎜à partir de la Page d'accueil–><code>Page de liste
–>Page de détails sur l'entreprise
–>Retour à la page de liste (nécessite une mise en cache)
–> Retour à la page d'accueil (nécessite une mise en cache)
– >Entrez à nouveau dans la page de liste (aucune mise en cache requise)
À ce stade, vous pouvez contrôler le keep-alive de la page selon les besoins🎜🎜Définissez l'attribut <code>keepAlive dans le code de routage> pour déterminer si la mise en cache est nécessaire🎜<pre class="brush:js;toolbar:false;">beforeRouteEnter(to, from, next){
next(vm=>{
console.log(vm)
// 每次进入路由执行
vm.getData() // 获取数据
})
},</pre>🎜Utilisez <code>7c9485ff8c3cba5ae9343ed63c2dc3f7
🎜activated(){ this.getData() // 获取数据 },
keep -alive
est un composant intégré à vue
🎜🎜Emplacement du code source : src/core/components/ keep-alive.js🎜rrreee🎜Vous pouvez voir que ce composant n'a pas de template, utilisez plutôt <code>render
, qui exécutera automatiquement le render
fonction lorsque le composant est rendu🎜🎜this.cache
est un objet Utilisé pour stocker les composants qui doivent être mis en cache, il sera stocké sous la forme suivante : 🎜rrreee🎜Exécutez le . fonction pruneCacheEntry
lorsque le composant est détruit 🎜rrreee🎜Observer dans la fonction hook montée
include et exclude
sont les suivants : 🎜rrreee🎜Si include
ou exclude
change, cela signifie que la définition doit Si les règles des composants mis en cache ou les règles des composants qui n'ont pas besoin d'être mis en cache ont changé , puis exécutez la fonction pruneCache
. La fonction est la suivante : 🎜rrreee🎜Dans cette fonction, mettez à jour this.cache
Parcourez l'objet, retirez le nom<.> de chaque élément et utilisez-le pour correspondre à la nouvelle règle de mise en cache. Si cela ne correspond pas, cela signifie que le composant n'a plus besoin d'être mis en cache sous la nouvelle règle de mise en cache, puis appelez <code>pruneCacheEntry<.> pour le supprimer de l'objet <code>this.cache
🎜🎜La fonction de mise en cache la plus puissante de keep-alive
est implémentée dans le render
fonction 🎜🎜Récupérez d'abord la valeur key
du composant : 🎜rrreee🎜Après avoir obtenu la valeur key
, accédez à l'objet this.cache pour recherchez s'il existe cette valeur, cela signifie que le composant a un cache, c'est-à-dire qu'il accède au cache, comme suit : 🎜<pre class="brush:js;toolbar:false;">/* 如果命中缓存,则直接从缓存中拿 vnode 的组件实例 */
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
/* 调整该组件key的顺序,将其从原来的地方删掉并重新放在最后一个 */
remove(keys, key)
keys.push(key)
}</pre><p>直接从缓存中拿 <code>vnode
的组件实例,此时重新调整该组件key
的顺序,将其从原来的地方删掉并重新放在this.keys
中最后一个
this.cache
对象中没有该key
值的情况,如下:
/* 如果没有命中缓存,则将其设置进缓存 */ else { cache[key] = vnode keys.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
,如果超过了,则把第一个缓存组件删掉
解决方案可以有以下两种:
每次组件渲染的时候,都会执行beforeRouteEnter
beforeRouteEnter(to, from, next){ next(vm=>{ console.log(vm) // 每次进入路由执行 vm.getData() // 获取数据 }) },
在keep-alive
缓存的组件被激活的时候,都会执行actived
钩子
activated(){ this.getData() // 获取数据 },
注意:服务器端渲染期间avtived
不被调用
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!