Maison > interface Web > Voir.js > Parlons de la compréhension du composant intégré keep-alive de Vue

Parlons de la compréhension du composant intégré keep-alive de Vue

青灯夜游
Libérer: 2022-12-14 20:15:39
avant
1942 Les gens l'ont consulté

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 !

Parlons de la compréhension du composant intégré keep-alive de Vue

1. Qu'est-ce que Keep-alive

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-alivevue中的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM 。【相关推荐:vuejs视频教程web前端开发

keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

keep-alive可以设置以下props属性:

  • include - 字符串或正则表达式。只有名称匹配的组件会被缓存
  • exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存
  • max - 数字。最多可以缓存多少组件实例

关于keep-alive的基本用法:

<keep-alive>
  <component :is="view"></component>
</keep-alive>
Copier après la connexion

使用includesexclude

<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="[&#39;a&#39;, &#39;b&#39;]">
  <component :is="view"></component>
</keep-alive>
Copier après la connexion

匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值),匿名组件不能被匹配

设置了 keep-alive 缓存的组件,会多出两个生命周期钩子(activateddeactivated):

  • 首次进入组件时:beforeRouteEnter > beforeCreate > created> mounted > activated > ... ... > beforeRouteLeave > deactivated
  • 再次进入组件时:beforeRouteEnter >activated > ... ... > beforeRouteLeave > deactivated

二、使用场景

使用原则:当我们在某些场景下不需要让页面重新加载时我们可以使用keepalive

举个栗子:

当我们从首页–>列表页–>商详页–>再返回,这时候列表页应该是需要keep-alive

首页–>列表页–>商详页–>返回到列表页(需要缓存)–>返回到首页(需要缓存)–>再次进入列表页(不需要缓存),这时候可以按需来控制页面的keep-alive

在路由中设置keepAlive属性判断是否需要缓存

{
  path: &#39;list&#39;,
  name: &#39;itemList&#39;, // 列表页
  component (resolve) {
    require([&#39;@/pages/item/list&#39;], resolve)
 },
 meta: {
  keepAlive: true,
  title: &#39;列表页&#39;
 }
}
Copier après la connexion

使用<keep-alive>

<div id="app" class=&#39;wrapper&#39;>
    <keep-alive>
        <!-- 需要缓存的视图组件 --> 
        <router-view v-if="$route.meta.keepAlive"></router-view>
     </keep-alive>
      <!-- 不需要缓存的视图组件 -->
     <router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
Copier après la connexion

三、原理分析

keep-alivevue中内置的一个组件

源码位置:src/core/components/keep-alive.js

export default {
  name: &#39;keep-alive&#39;,
  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(&#39;include&#39;, val => {
      pruneCache(this, name => matches(val, name))
    })
    this.$watch(&#39;exclude&#39;, 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}` : &#39;&#39;)
        : 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])
  }
}
Copier après la connexion

可以看到该组件没有template,而是用了render,在组件渲染的时候会自动执行render函数

this.cache是一个对象,用来存储需要缓存的组件,它将以如下形式存储:

this.cache = {
    &#39;key1&#39;:&#39;组件1&#39;,
    &#39;key2&#39;:&#39;组件2&#39;,
    // ...
}
Copier après la connexion

在组件销毁的时候执行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)
}
Copier après la connexion

mounted钩子函数中观测 includeexclude 的变化,如下:

mounted () {
    this.$watch(&#39;include&#39;, val => {
        pruneCache(this, name => matches(val, name))
    })
    this.$watch(&#39;exclude&#39;, val => {
        pruneCache(this, name => !matches(val, name))
    })
}
Copier après la connexion

如果includeexclude 发生了变化,即表示定义需要缓存的组件的规则或者不需要缓存的组件的规则发生了变化,那么就执行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)
      }
    }
  }
}
Copier après la connexion

在该函数内对this.cache对象进行遍历,取出每一项的name值,用其与新的缓存规则进行匹配,如果匹配不上,则表示在新的缓存规则下该组件已经不需要被缓存,则调用pruneCacheEntry函数将其从this.cache对象剔除即可

关于keep-alive的最强大缓存功能是在render函数中实现

首先获取组件的key值:

const key = vnode.key == null? 
componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : &#39;&#39;)
: vnode.key
Copier après la connexion

拿到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 cache
  • max - nombre. Le nombre maximum d'instances de composants pouvant être mises en cache
🎜Utilisation de base de keep-alive : 🎜
/* 如果命中缓存,则直接从缓存中拿 vnode 的组件实例 */
if (cache[key]) {
    vnode.componentInstance = cache[key].componentInstance
    /* 调整该组件key的顺序,将其从原来的地方删掉并重新放在最后一个 */
    remove(keys, key)
    keys.push(key)
}
Copier après la connexion
Copier après la connexion
🎜Utilisez includes et exclude </code > : 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">/* 如果没有命中缓存,则将其设置进缓存 */ else { cache[key] = vnode keys.push(key) /* 如果配置了max并且缓存的长度超过了this.max,则从缓存中删除第一个 */ if (this.max &amp;&amp; keys.length &gt; parseInt(this.max)) { pruneCacheEntry(cache, keys[0], keys, this._vnode) } }</pre><div class="contentsignin">Copier après la connexion</div></div><div class="contentsignin">Copier après la connexion</div></div>🎜La correspondance vérifie d'abord l'option <code>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é ): 🎜
  • Lors de la première saisie du composant : beforeRouteEnter > beforeCreate > > monté</ code> > <code>activé > ... ... > li>
  • Entrez à nouveau le composant Quand : beforeRouteEnter >activé > ... ... > code>désactivé

🎜2. Scénarios d'utilisation🎜🎜🎜Principe d'utilisation : Lorsqu'on n'a pas besoin de recharger la page dans Dans certains scénarios, nous pouvons utiliser 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. >–><code>Page de liste</code >–><code>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 keepAlive pour déterminer si la mise en cache est nécessaire🎜
beforeRouteEnter(to, from, next){
    next(vm=>{
        console.log(vm)
        // 每次进入路由执行
        vm.getData()  // 获取数据
    })
},
Copier après la connexion
Copier après la connexion
🎜Utilisez <keep-alive>🎜
activated(){
   this.getData() // 获取数据
},
Copier après la connexion
Copier après la connexion

🎜3. Analyse des principes🎜🎜🎜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< /code>, utilisez plutôt <code>render, qui exécutera automatiquement le render</code > fonction lorsque le composant est rendu🎜🎜<code>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 < Les changements dans code>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.cacheParcourez l'objet, retirez le nom<. /code> 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<. /code> 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</code > fonction 🎜🎜Récupérez d'abord la valeur <code>key du composant : 🎜rrreee🎜Après avoir obtenu la valeur key, accédez à l'objet this.cache< /code> 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 : 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">/* 如果命中缓存,则直接从缓存中拿 vnode 的组件实例 */ if (cache[key]) { vnode.componentInstance = cache[key].componentInstance /* 调整该组件key的顺序,将其从原来的地方删掉并重新放在最后一个 */ remove(keys, key) keys.push(key) }</pre><div class="contentsignin">Copier après la connexion</div></div><div class="contentsignin">Copier après la connexion</div></div><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)
    }
}
Copier après la connexion
Copier après la connexion

表明该组件还没有被缓存过,则以该组件的key为键,组件vnode为值,将其存入this.cache中,并且把key存入this.keys

此时再判断this.keys中缓存组件的数量是否超过了设置的最大缓存数量值this.max,如果超过了,则把第一个缓存组件删掉

四、思考题:缓存后如何获取数据

解决方案可以有以下两种:

  • beforeRouteEnter
  • actived

beforeRouteEnter

每次组件渲染的时候,都会执行beforeRouteEnter

beforeRouteEnter(to, from, next){
    next(vm=>{
        console.log(vm)
        // 每次进入路由执行
        vm.getData()  // 获取数据
    })
},
Copier après la connexion
Copier après la connexion

actived

keep-alive缓存的组件被激活的时候,都会执行actived钩子

activated(){
   this.getData() // 获取数据
},
Copier après la connexion
Copier après la connexion

注意:服务器端渲染期间avtived不被调用

(学习视频分享:vuejs入门教程编程基础视频

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!

Étiquettes associées:
source:juejin.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal