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

keep-alive保持組件狀態(tài)的方法

 更新時間:2020年12月02日 09:35:49   作者:快狗打車前端團隊  
這篇文章主要介紹了keep-alive保持組件狀態(tài)的方法,幫助大家更好的理解和學(xué)習vue框架,感興趣的朋友可以了解下

keep-alive的設(shè)計初衷

有些業(yè)務(wù)場景需要根據(jù)不同的判斷條件,動態(tài)地在多個組件之間切換。頻繁的組件切換會導(dǎo)致組件反復(fù)渲染,如果組件包含有大量的邏輯和dom節(jié)點,極易造成性能問題。其次,切換后組件的狀態(tài)也會完全丟失。keep-alive的設(shè)計初衷就是為了保持組件的狀態(tài),避免組件的重復(fù)渲染。

為什么keep-alive可以直接使用

開發(fā)者無需注冊和引入,直接可以在模板中使用。 跟開發(fā)者使用Vue.component自定義的組件不同,keep-alive無需注冊,在模板中直接可以使用,如下所示:

<keep-alive>
 <component :is="view"></component>
</keep-alive>

這是因為keep-alive是vue的內(nèi)置組件,已經(jīng)在vue中提前定義。

// core/components/keep-alive.js

export default {
 name: 'keep-alive',
 abstract: true,

 props: {
  include: patternTypes,
  exclude: patternTypes,
  max: [String, Number]
 },

 created () {
  this.cache = Object.create(null)
  this.keys = []
 },

 destroyed () {
  // keep-alive的銷毀,將所有緩存的組件清除
  for (const key in this.cache) {
   pruneCacheEntry(this.cache, key, this.keys)
  }
 },

 mounted () {
  // 如果指定了include和exclude屬性,需要實時觀察當前這兩個屬性的變化,以及時的更新緩存
  this.$watch('include', val => {
   pruneCache(this, name => matches(val, name))
  })
  this.$watch('exclude', val => {
   pruneCache(this, name => !matches(val, name))
  })
 },

 render () {
  // keepAlive組件本身不會被渲染成dom節(jié)點,其render方法的處理邏輯的是將其包裹的組件的vnode返回
  const slot = this.$slots.default
  // 獲取第一個組件子節(jié)點
  const vnode: VNode = getFirstComponentChild(slot)
  const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
  if (componentOptions) {
   // check pattern
   const name: ?string = getComponentName(componentOptions)
   const { include, exclude } = this
   if (
    // not included
    (include && (!name || !matches(include, name))) ||
    // excluded
    (exclude && name && matches(exclude, name))
   ) {
    return vnode
   }

   const { cache, keys } = this
   const key: ?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

   // 1、如果緩存中存在該vnode,從緩存中取得該組件的實例(一個組件對應(yīng)一顆vnode樹,同時一個組件對應(yīng)一個vue子類的實例),不再重新創(chuàng)建
   if (cache[key]) {
    vnode.componentInstance = cache[key].componentInstance
    // make current key freshest
    // 將當前的組件的key作為最新的緩存(更新其在keys數(shù)組中的順序)
    remove(keys, key)
    keys.push(key)
   } else {
    // 2、如果未命中緩存,添加到緩存
    cache[key] = vnode
    keys.push(key)
    // 如果緩存超過限制,淘汰最舊的緩存
    if (this.max && keys.length > parseInt(this.max)) {
     pruneCacheEntry(cache, keys[0], keys, this._vnode)
    }
   }

   // 標記為keepAlive組件
   vnode.data.keepAlive = true
  }
  return vnode || (slot && slot[0])
 }
}

這是因為keep-alive是vue的內(nèi)置組件,已經(jīng)在vue中提前定義。

// core/components/keep-alive.js

export default {
 name: 'keep-alive',
 abstract: true,

 props: {
  include: patternTypes,
  exclude: patternTypes,
  max: [String, Number]
 },

 created () {
  this.cache = Object.create(null)
  this.keys = []
 },

 destroyed () {
  // keep-alive的銷毀,將所有緩存的組件清除
  for (const key in this.cache) {
   pruneCacheEntry(this.cache, key, this.keys)
  }
 },

 mounted () {
  // 如果指定了include和exclude屬性,需要實時觀察當前這兩個屬性的變化,以及時的更新緩存
  this.$watch('include', val => {
   pruneCache(this, name => matches(val, name))
  })
  this.$watch('exclude', val => {
   pruneCache(this, name => !matches(val, name))
  })
 },

 render () {
  // keepAlive組件本身不會被渲染成dom節(jié)點,其render方法的處理邏輯的是將其包裹的組件的vnode返回
  const slot = this.$slots.default
  // 獲取第一個組件子節(jié)點
  const vnode: VNode = getFirstComponentChild(slot)
  const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
  if (componentOptions) {
   // check pattern
   const name: ?string = getComponentName(componentOptions)
   const { include, exclude } = this
   if (
    // not included
    (include && (!name || !matches(include, name))) ||
    // excluded
    (exclude && name && matches(exclude, name))
   ) {
    return vnode
   }

   const { cache, keys } = this
   const key: ?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

   // 1、如果緩存中存在該vnode,從緩存中取得該組件的實例(一個組件對應(yīng)一顆vnode樹,同時一個組件對應(yīng)一個vue子類的實例),不再重新創(chuàng)建
   if (cache[key]) {
    vnode.componentInstance = cache[key].componentInstance
    // make current key freshest
    // 將當前的組件的key作為最新的緩存(更新其在keys數(shù)組中的順序)
    remove(keys, key)
    keys.push(key)
   } else {
    // 2、如果未命中緩存,添加到緩存
    cache[key] = vnode
    keys.push(key)
    // 如果緩存超過限制,淘汰最舊的緩存
    if (this.max && keys.length > parseInt(this.max)) {
     pruneCacheEntry(cache, keys[0], keys, this._vnode)
    }
   }

   // 標記為keepAlive組件
   vnode.data.keepAlive = true
  }
  return vnode || (slot && slot[0])
 }
}

// core/components/index.js
import KeepAlive from './keep-alive'

export default {
 KeepAlive
}

// core/global-api/index.js

// 導(dǎo)入內(nèi)置組件
import builtInComponents from '../components/index'

/**
 * 為Vue添加全局方法和屬性
 * @param {GlobalAPI} Vue 
 */
export function initGlobalAPI (Vue: GlobalAPI) {
 
 // ...省略了無關(guān)代碼
 
 Vue.options = Object.create(null)
 // 添加內(nèi)置組件keep-alive
 extend(Vue.options.components, builtInComponents)
}

buildInComponents中包含了keep-alive的定義。在initGlobalAPI方法中,將內(nèi)置組件添加到了 vue的全局變量中。

extend(A, B)是個簡單的對象屬性復(fù)制方法。將對象B中的屬性復(fù)制到對象A中。

keep-alive是如何保持組件狀態(tài)的

為了保持組件狀態(tài),keep-alive設(shè)計了緩存機制。

我們知道,模板中的每個HTML標簽在vue中由相應(yīng)的vnode節(jié)點對象來表示。如果是HTML標簽是組件標簽,需要為該標簽的vnode創(chuàng)建一個組件實例。組件實例負責組件內(nèi)的HTML模板的編譯和渲染。因此相比于普通HTML標簽的vnode節(jié)點,組件vnode節(jié)點會存在componentOptions和 componentInstance 這兩個屬性中保存組件選項對象和組件實例的引用。

首先,我們從keep-alive組件的實現(xiàn)代碼中可以看到在組件的created鉤子中設(shè)計了緩存機制:

created () {
  this.cache = Object.create(null)
  this.keys = []
}

keep-alive設(shè)置了cache和keys兩個屬性來緩存子組件。其中cache中的每項是一個以所包裹的組件的組件名為key,包裹組件對應(yīng)的vnoded為值的對象。keys的每一項是其所包裹的組件的組件名。

render 函數(shù)是vue實例和vue組件實例中用來創(chuàng)建vnode的方法。我們在實際的應(yīng)用中,一般是通過template和el來指定模板,然后由vue將模板編譯成render函數(shù)。如果用戶希望能更靈活地控制vnode的創(chuàng)建可以提供自定義的render函數(shù)。

render () {
  const slot = this.$slots.default
  // 獲取第一個組件子節(jié)點
  const vnode: VNode = getFirstComponentChild(slot)
  const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
  if (componentOptions) {
   // check pattern
   const name: ?string = getComponentName(componentOptions)
   const { include, exclude } = this
   if (
    // not included
    (include && (!name || !matches(include, name))) ||
    // excluded
    (exclude && name && matches(exclude, name))
   ) {
    return vnode
   }

   const { cache, keys } = this
   const key: ?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

   // 1、如果緩存中存在該vnode,從緩存中取得該組件的實例(一個組件對應(yīng)一顆vnode樹,同時一個組件對應(yīng)一個vue子類的實例),不再重新創(chuàng)建
   if (cache[key]) {
    vnode.componentInstance = cache[key].componentInstance
    // make current key freshest
    // 將當前的組件的key作為最新的緩存(更新其在keys數(shù)組中的順序)
    remove(keys, key)
    keys.push(key)
   } else {
    // 2、如果未命中緩存,添加到緩存
    cache[key] = vnode
    keys.push(key)
    // 如果緩存超過限制,淘汰最舊的緩存
    if (this.max && keys.length > parseInt(this.max)) {
     pruneCacheEntry(cache, keys[0], keys, this._vnode)
    }
   }

   // 標記為keepAlive組件
   vnode.data.keepAlive = true
  }
  return vnode || (slot && slot[0])
 }

keep-alive內(nèi)部就是單獨提供了render函數(shù)來自定義了vnode的創(chuàng)建邏輯。首先keep-alive獲取到其所包裹的子組件的根vnode,然后去cache中查找該組件是否存在。

如果cache中不存在子組件vnode,則以{子組件名: 子組件vnode}的形式保存到cache對象中。同時將子組件名字保存到keys數(shù)組中。同時如果當前緩存的數(shù)量已經(jīng)超過max所設(shè)置的最大值,需要淘汰掉最近最少使用的緩存項(LRU)。

如果cache中存在子組件vnode,那么只需要復(fù)用緩存的組件vnode的組件實例(componentInstance)。同時需要將該子組件vnode在緩存中順序調(diào)到最前面,這個主要是為了在緩存不足時,正確地淘汰緩存項。

舉例說明

最后通過一個例子加深一下理解。

 <div id="app">
  <keep-alive><component :is="view"></component></keep-alive>
  <button @click="view = view =='count'? 'any': 'count'">切換組件</button>
</div>
Vue.component("count", {
  data() {
    return {
      count:0
    };
  },
  template: "<div @click='count+=1'>點了我 {{count}} 次</div>"
});
  
Vue.component("any", {
  template: "<div>any</div>"
});

new Vue({
  el: "#app",
  data: {
   view: "count"
  }
});

由于view默認值是count,因此keep-alive包裹的子組件是count。此時keep-alive的緩存中為空,因此會把組件count的vnode添加到緩存。緩存結(jié)果為

cache = {1::count: {tag: "vue-component-1-count", data:{tag: "component", hook: {…}}}, componentOptions, componentInstance, ...}
keys = ["1::count"]

點擊一下組件count,組件的顯示內(nèi)容變成"點了我1次",然后切換到組件any。與count組件相同,由于在keep-alive的緩存中還未保存any組件的vnode,因此需要將any添加到緩存中。此時緩存結(jié)果變成了:

cache = {
  1::count: {tag: "vue-component-1-count", data:{tag: "component", hook: {…}}, componentOptions, componentInstance, ...},
  2::any: {tag: "vue-component-2-any", data:{tag: "component", hook: {…}}, componentOptions, componentInstance, ...},
}
keys = ["1::count", "2::any"]

頁面顯示結(jié)果為:

再次點擊切換組件,切回count。此時count組件的vnode在緩存中已經(jīng)存在,所以直接復(fù)用了原來count組件vnode中所保存的組件實例,組件實例中保存了原來的count值,因此組件切換完后,組件的狀態(tài)也跟著還原了回來。

下圖為count組件實例的狀態(tài),可以看到count的值得到了保持:

最終頁面顯示結(jié)果為:

從上面的分析可知,如果組件被包裹在keep-alive組件中,組件vnode會緩存到cache中。而組件的狀態(tài)又會保存在組件實例中(componentInstance),當組件再次切換回來時,keep-alive直接將之前緩存的狀態(tài)進行還原,也就實現(xiàn)了組件狀態(tài)的保持。

以上就是keep-alive保持組件狀態(tài)的方法的詳細內(nèi)容,更多關(guān)于keep-alive保持組件狀態(tài)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue3中實現(xiàn)網(wǎng)頁時鐘功能(顯示當前時間并每秒更新一次)

    Vue3中實現(xiàn)網(wǎng)頁時鐘功能(顯示當前時間并每秒更新一次)

    本文將詳細介紹如何在Vue3中實現(xiàn)一個每秒鐘自動更新的網(wǎng)頁時鐘,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-07-07
  • vue實現(xiàn)Excel文件的上傳與下載功能的兩種方式

    vue實現(xiàn)Excel文件的上傳與下載功能的兩種方式

    這篇文章主要介紹了vue實現(xiàn)Excel文件的上傳與下載功能,本文通過兩種方式給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-06-06
  • VUE引入第三方j(luò)s包及調(diào)用方法講解

    VUE引入第三方j(luò)s包及調(diào)用方法講解

    今天小編就為大家分享一篇關(guān)于VUE引入第三方j(luò)s包及調(diào)用方法講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • 基于vue-cli3創(chuàng)建libs庫的實現(xiàn)方法

    基于vue-cli3創(chuàng)建libs庫的實現(xiàn)方法

    這篇文章主要介紹了基于vue-cli3創(chuàng)建libs庫的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2019-12-12
  • element-plus+Vue3實現(xiàn)表格數(shù)據(jù)動態(tài)渲染

    element-plus+Vue3實現(xiàn)表格數(shù)據(jù)動態(tài)渲染

    在Vue中,el-table是element-ui提供的強大表格組件,可以用于展示靜態(tài)和動態(tài)表格數(shù)據(jù),本文主要介紹了element-plus+Vue3實現(xiàn)表格數(shù)據(jù)動態(tài)渲染,感興趣的可以了解一下
    2024-03-03
  • vue2+elementUI的el-tree的選中、高亮、定位功能的實現(xiàn)

    vue2+elementUI的el-tree的選中、高亮、定位功能的實現(xiàn)

    這篇文章主要介紹了vue2+elementUI的el-tree的選中、高亮、定位功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • vue2前端導(dǎo)出pdf文件實例demo

    vue2前端導(dǎo)出pdf文件實例demo

    在Vue應(yīng)用中,將頁面導(dǎo)出為PDF文件通常涉及到前端技術(shù)的組合,下面這篇文章主要給大家介紹了關(guān)于vue2前端導(dǎo)出pdf文件的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-09-09
  • vue項目中input輸入框輸入不了值問題及解決

    vue項目中input輸入框輸入不了值問題及解決

    這篇文章主要介紹了vue項目中input輸入框輸入不了值問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 詳解vue-class遷移vite的一次踩坑記錄

    詳解vue-class遷移vite的一次踩坑記錄

    本文主要介紹了vue-class遷移vite的一次踩坑記錄,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • vue2.0 computed 計算list循環(huán)后累加值的實例

    vue2.0 computed 計算list循環(huán)后累加值的實例

    下面小編就為大家分享一篇vue2.0 computed 計算list循環(huán)后累加值的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03

最新評論

金溪县| 武汉市| 丰原市| 临猗县| 疏勒县| 临桂县| 双江| 德庆县| 彰化县| 都江堰市| 禄丰县| 枞阳县| 神农架林区| 吴堡县| 南丹县| 增城市| 朝阳区| 上虞市| 临清市| 红原县| 防城港市| 托里县| 阿拉善盟| 东明县| 广安市| 清镇市| 尚志市| 石台县| 龙岩市| 九江县| 五原县| 四平市| 玉溪市| 五河县| 广宁县| 龙山县| 广昌县| 旅游| 沁源县| 大足县| 嘉兴市|