国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務(wù)器之家 - 編程語言 - JavaScript - keep-alive保持組件狀態(tài)的方法

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

2021-11-26 15:55快狗打車前端團(tuán)隊(duì) JavaScript

這篇文章主要介紹了keep-alive保持組件狀態(tài)的方法,幫助大家更好的理解和學(xué)習(xí)vue框架,感興趣的朋友可以了解下

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

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

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

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

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

這是因?yàn)閗eep-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屬性,需要實(shí)時(shí)觀察當(dāng)前這兩個(gè)屬性的變化,以及時(shí)的更新緩存
  this.$watch("include", val => {
   pruneCache(this, name => matches(val, name))
  })
  this.$watch("exclude", val => {
   pruneCache(this, name => !matches(val, name))
  })
 },

 render () {
  // keepAlive組件本身不會(huì)被渲染成dom節(jié)點(diǎn),其render方法的處理邏輯的是將其包裹的組件的vnode返回
  const slot = this.$slots.default
  // 獲取第一個(gè)組件子節(jié)點(diǎn)
  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,從緩存中取得該組件的實(shí)例(一個(gè)組件對(duì)應(yīng)一顆vnode樹,同時(shí)一個(gè)組件對(duì)應(yīng)一個(gè)vue子類的實(shí)例),不再重新創(chuàng)建
   if (cache[key]) {
    vnode.componentInstance = cache[key].componentInstance
    // make current key freshest
    // 將當(dāng)前的組件的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)
    }
   }

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

這是因?yàn)閗eep-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屬性,需要實(shí)時(shí)觀察當(dāng)前這兩個(gè)屬性的變化,以及時(shí)的更新緩存
  this.$watch("include", val => {
   pruneCache(this, name => matches(val, name))
  })
  this.$watch("exclude", val => {
   pruneCache(this, name => !matches(val, name))
  })
 },

 render () {
  // keepAlive組件本身不會(huì)被渲染成dom節(jié)點(diǎn),其render方法的處理邏輯的是將其包裹的組件的vnode返回
  const slot = this.$slots.default
  // 獲取第一個(gè)組件子節(jié)點(diǎn)
  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,從緩存中取得該組件的實(shí)例(一個(gè)組件對(duì)應(yīng)一顆vnode樹,同時(shí)一個(gè)組件對(duì)應(yīng)一個(gè)vue子類的實(shí)例),不再重新創(chuàng)建
   if (cache[key]) {
    vnode.componentInstance = cache[key].componentInstance
    // make current key freshest
    // 將當(dāng)前的組件的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)
    }
   }

   // 標(biāo)記為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)是個(gè)簡單的對(duì)象屬性復(fù)制方法。將對(duì)象B中的屬性復(fù)制到對(duì)象A中。

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

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

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

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

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

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

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

render () {
  const slot = this.$slots.default
  // 獲取第一個(gè)組件子節(jié)點(diǎn)
  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,從緩存中取得該組件的實(shí)例(一個(gè)組件對(duì)應(yīng)一顆vnode樹,同時(shí)一個(gè)組件對(duì)應(yīng)一個(gè)vue子類的實(shí)例),不再重新創(chuàng)建
   if (cache[key]) {
    vnode.componentInstance = cache[key].componentInstance
    // make current key freshest
    // 將當(dāng)前的組件的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)
    }
   }

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

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

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

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

舉例說明

最后通過一個(gè)例子加深一下理解。

 <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">點(diǎn)了我 {{count}} 次</div>"
});
  
Vue.component("any", {
  template: "<div>any</div>"
});

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

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

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

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

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

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

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

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

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

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

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

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

以上就是keep-alive保持組件狀態(tài)的方法的詳細(xì)內(nèi)容,更多關(guān)于keep-alive保持組件狀態(tài)的資料請(qǐng)關(guān)注服務(wù)器之家其它相關(guān)文章!

原文鏈接:https://juejin.cn/post/6901224360783446030?utm_source=tuicool&utm_medium=referral

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 不用播放器的免费av | 久久精品中文字幕 | 不卡免费在线视频 | 99在线视频播放 | 中文字幕免费视频 | 亚洲免费视频在线 | 中文字幕在线综合 | 久久久国产精品一区 | 亚洲免费观看视频 | 欧美二区三区视频 | 成人免费视频7777777 | 中文字幕一区日韩精品欧美 | а天堂中文最新一区二区三区 | 欧美一区免费 | 日韩在线观看中文 | av一级毛片 | 欧美一级免费 | 国产精品网站在线观看 | 成人伊人 | 国产中文字幕在线观看 | 毛片黄片免费观看 | 欧美激情一区二区三级高清视频 | 一区二区精品在线 | 久久综合av | 国内自拍视频在线观看 | 免费观看黄视频 | 成人网页在线 | 国产精品久久久久久一区 | 羞羞视频免费观看网站 | 国产人成在线观看 | 天天精品 | 久热久 | 亚洲福利片 | 欧洲精品一区 | 在线免费黄色网址 | 国产精品久久久久久久久久久免费看 | 少妇自摸视频 | 伊人中文| 国产精品久久久久久久久久大牛 | 国产精品成人一区二区三区 | 日韩在线成人 |