最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解Vue中keep-alive的實(shí)現(xiàn)原理

 更新時(shí)間:2025年10月30日 10:08:27   作者:阿珊和她的貓  
在 Vue.js 開發(fā)單頁(yè)面應(yīng)用(SPA)時(shí),組件的頻繁創(chuàng)建和銷毀會(huì)帶來(lái)一定的性能開銷,為了優(yōu)化這一問(wèn)題,Vue 提供了 keep-alive 組件,本文將深入剖析 keep-alive 的實(shí)現(xiàn)原理,需要的朋友可以參考下

引言

在 Vue.js 開發(fā)單頁(yè)面應(yīng)用(SPA)時(shí),組件的頻繁創(chuàng)建和銷毀會(huì)帶來(lái)一定的性能開銷。為了優(yōu)化這一問(wèn)題,Vue 提供了 keep-alive 組件。keep-alive 可以將包裹在其中的組件實(shí)例進(jìn)行緩存,避免重復(fù)創(chuàng)建和銷毀,從而提升應(yīng)用的性能和用戶體驗(yàn)。本文將深入剖析 keep-alive 的實(shí)現(xiàn)原理。

keep-alive 的基本使用

keep-alive 是一個(gè)內(nèi)置組件,使用時(shí)只需將需要緩存的組件包裹在 <keep-alive> 標(biāo)簽內(nèi)。示例如下:

<template>
  <div>
    <keep-alive>
      <component :is="currentComponent"></component>
    </keep-alive>
    <button @click="toggleComponent">切換組件</button>
  </div>
</template>

<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';

export default {
  data() {
    return {
      currentComponent: 'ComponentA'
    };
  },
  components: {
    ComponentA,
    ComponentB
  },
  methods: {
    toggleComponent() {
      this.currentComponent = this.currentComponent === 'ComponentA' ? 'ComponentB' : 'ComponentA';
    }
  }
};
</script>

在上述代碼中,ComponentA 和 ComponentB 會(huì)被 keep-alive 緩存,切換時(shí)不會(huì)重新創(chuàng)建。

keep-alive 的實(shí)現(xiàn)原理

1. 緩存機(jī)制

keep-alive 內(nèi)部使用一個(gè)對(duì)象 cache 來(lái)存儲(chǔ)緩存的組件實(shí)例,鍵為組件的唯一標(biāo)識(shí),值為組件實(shí)例。同時(shí),使用一個(gè)數(shù)組 keys 來(lái)存儲(chǔ)這些組件的鍵,用于管理緩存的順序。

2. 組件渲染過(guò)程

當(dāng) keep-alive 包裹的組件首次渲染時(shí),keep-alive 會(huì)正常創(chuàng)建組件實(shí)例,并將其緩存到 cache 對(duì)象中,同時(shí)將對(duì)應(yīng)的鍵添加到 keys 數(shù)組。當(dāng)再次渲染該組件時(shí),keep-alive 會(huì)從 cache 中取出緩存的組件實(shí)例進(jìn)行渲染,而不是重新創(chuàng)建。

3. 生命周期鉤子

keep-alive 會(huì)影響組件的生命周期鉤子。被緩存的組件在首次進(jìn)入時(shí)會(huì)觸發(fā) activated 鉤子,在離開時(shí)會(huì)觸發(fā) deactivated 鉤子,而不是 mounted 和 destroyed。這是因?yàn)榻M件實(shí)例并沒(méi)有被真正銷毀,只是被隱藏了起來(lái)。

4. 源碼分析

以下是簡(jiǎn)化后的 keep-alive 源碼分析:

export default {
  name: 'keep-alive',
  abstract: true, // 抽象組件,不會(huì)渲染到 DOM 中
  props: {
    include: [String, RegExp, Array], // 包含的組件名稱
    exclude: [String, RegExp, Array], // 排除的組件名稱
    max: [String, Number] // 最大緩存數(shù)量
  },
  created() {
    this.cache = Object.create(null); // 初始化緩存對(duì)象
    this.keys = []; // 初始化鍵數(shù)組
  },
  destroyed() {
    for (const key in this.cache) {
      // 銷毀緩存的組件實(shí)例
      this.pruneCacheEntry(this.cache[key]);
    }
  },
  mounted() {
    // 監(jiān)聽 include 和 exclude 的變化
    this.$watch('include', val => {
      this.pruneCache(name => matches(val, name));
    });
    this.$watch('exclude', val => {
      this.pruneCache(name =>!matches(val, name));
    });
  },
  render() {
    const vnode = getFirstComponentChild(this.$slots.default); // 獲取第一個(gè)子組件的虛擬節(jié)點(diǎn)
    const componentOptions = vnode && vnode.componentOptions;
    if (componentOptions) {
      const name = getComponentName(componentOptions); // 獲取組件名稱
      const { include, exclude } = this;
      if (
        // 判斷是否需要緩存
        (include && (!name ||!matches(include, name))) ||
        (exclude && name && matches(exclude, name))
      ) {
        return vnode;
      }

      const { cache, keys } = this;
      const key = vnode.key == null
        ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
        : vnode.key;
      if (cache[key]) {
        // 從緩存中獲取組件實(shí)例
        vnode.componentInstance = cache[key].componentInstance;
        // 調(diào)整緩存順序
        remove(keys, key);
        keys.push(key);
      } else {
        // 緩存新的組件實(shí)例
        cache[key] = vnode;
        keys.push(key);
        // 超過(guò)最大緩存數(shù)量時(shí),移除最早的緩存
        if (this.max && keys.length > parseInt(this.max)) {
          this.pruneCacheEntry(keys[0]);
        }
      }

      vnode.data.keepAlive = true; // 標(biāo)記組件被緩存
    }
    return vnode;
  },
  methods: {
    pruneCache(filter) {
      for (const key in this.cache) {
        const cachedNode = this.cache[key];
        if (cachedNode) {
          const name = getComponentName(cachedNode.componentOptions);
          if (name &&!filter(name)) {
            this.pruneCacheEntry(cachedNode);
          }
        }
      }
    },
    pruneCacheEntry(vnode) {
      if (vnode) {
        // 銷毀組件實(shí)例
        vnode.componentInstance.$destroy();
        this.cache[vnode.key] = null;
        remove(this.keys, vnode.key);
      }
    }
  }
};

代碼解釋

  • abstract: true:表明 keep-alive 是一個(gè)抽象組件,不會(huì)渲染到 DOM 中。
  • created 鉤子:初始化 cache 對(duì)象和 keys 數(shù)組。
  • destroyed 鉤子:銷毀所有緩存的組件實(shí)例。
  • mounted 鉤子:監(jiān)聽 include 和 exclude 的變化,根據(jù)條件清理緩存。
  • render 方法:
    • 獲取第一個(gè)子組件的虛擬節(jié)點(diǎn)。
    • 判斷是否需要緩存該組件。
    • 如果組件已緩存,從緩存中獲取實(shí)例并調(diào)整緩存順序。
    • 如果組件未緩存,將其添加到緩存中,并根據(jù) max 屬性判斷是否需要移除最早的緩存。
    • 標(biāo)記組件被緩存。
  • pruneCache 方法:根據(jù)過(guò)濾條件清理緩存。
  • pruneCacheEntry 方法:銷毀指定的組件實(shí)例并從緩存中移除。

總結(jié)

keep-alive 通過(guò)內(nèi)部的緩存機(jī)制,避免了組件的重復(fù)創(chuàng)建和銷毀,提升了應(yīng)用的性能。它通過(guò) cache 對(duì)象和 keys 數(shù)組來(lái)管理緩存,同時(shí)影響組件的生命周期鉤子。理解 keep-alive 的實(shí)現(xiàn)原理,有助于我們?cè)陂_發(fā)中更好地使用它,優(yōu)化應(yīng)用的性能和用戶體驗(yàn)。

以上就是一文詳解Vue中keep-alive的實(shí)現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于Vue keep-alive實(shí)現(xiàn)原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue改變數(shù)據(jù)后數(shù)據(jù)變化頁(yè)面不刷新的解決方法

    vue改變數(shù)據(jù)后數(shù)據(jù)變化頁(yè)面不刷新的解決方法

    這篇文章主要給大家介紹了關(guān)于vue改變數(shù)據(jù)后數(shù)據(jù)變化頁(yè)面不刷新的解決方法,vue比較常見的坑就是數(shù)據(jù)(后臺(tái)返回)更新了,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • Vue中使用ECharts與v-if的問(wèn)題和解決方案

    Vue中使用ECharts與v-if的問(wèn)題和解決方案

    在Vue項(xiàng)目中使用v-if指令控制ECharts圖表顯示時(shí),可能會(huì)遇到圖表無(wú)法正常渲染或顯示錯(cuò)誤的問(wèn)題,下面這篇文章主要介紹了Vue中使用ECharts與v-if的問(wèn)題和解決方案,需要的朋友可以參考下
    2024-10-10
  • Vue3+NodeJS+Soket.io實(shí)現(xiàn)實(shí)時(shí)聊天的示例代碼

    Vue3+NodeJS+Soket.io實(shí)現(xiàn)實(shí)時(shí)聊天的示例代碼

    本文主要介紹了Vue3+NodeJS+Soket.io實(shí)現(xiàn)實(shí)時(shí)聊天的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • vue中使用vue-pdf的方法詳解

    vue中使用vue-pdf的方法詳解

    這篇文章主要介紹了vue中使用vue-pdf的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • vue.js實(shí)例對(duì)象+組件樹的詳細(xì)介紹

    vue.js實(shí)例對(duì)象+組件樹的詳細(xì)介紹

    這篇文章主要介紹了vue.js實(shí)例對(duì)象+組件樹的相關(guān)資料,需要的朋友可以參考下
    2017-10-10
  • vue全家桶-vuex深入講解

    vue全家桶-vuex深入講解

    這篇文章主要介紹了vue全家桶-vuex深入講解,文章內(nèi)容詳細(xì),簡(jiǎn)單易懂,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2023-01-01
  • Vue+canvas實(shí)現(xiàn)水印功能

    Vue+canvas實(shí)現(xiàn)水印功能

    實(shí)際項(xiàng)目中偶爾會(huì)遇到給項(xiàng)目頁(yè)面背景加水印的需求,這篇文章主要為大家介紹了Vue使用canvas實(shí)現(xiàn)水印功能的示例代碼,希望對(duì)大家有所幫助
    2023-07-07
  • el-table表格排序(多列排序和遠(yuǎn)程排序)

    el-table表格排序(多列排序和遠(yuǎn)程排序)

    本文主要介紹了el-table表格排序(多列排序和遠(yuǎn)程排序),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Vue.config.js配置報(bào)錯(cuò)ValidationError:?Invalid?options?object解決辦法

    Vue.config.js配置報(bào)錯(cuò)ValidationError:?Invalid?options?object解

    這篇文章主要給大家介紹了關(guān)于Vue.config.js配置報(bào)錯(cuò)ValidationError:?Invalid?options?object的解決辦法,主要由于vue.config.js配置文件錯(cuò)誤導(dǎo)致的,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-02-02
  • Vue中的路由配置項(xiàng)meta使用解析

    Vue中的路由配置項(xiàng)meta使用解析

    這篇文章主要介紹了Vue中的路由配置項(xiàng)meta使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10

最新評(píng)論

噶尔县| 房产| 中山市| 石狮市| 江北区| 若尔盖县| 固原市| 信宜市| 岢岚县| 抚顺县| 德格县| 灵武市| 阳原县| 远安县| 兴业县| 波密县| 恩平市| 十堰市| 青岛市| 泸水县| 岳阳市| 西昌市| 青神县| 峨眉山市| 迭部县| 邢台市| 永安市| 呼玛县| 晋城| 三门县| 涞源县| 芮城县| 凤翔县| 龙门县| 深水埗区| 武山县| 阿克陶县| 大新县| 台南市| 孙吴县| 恩平市|