Vue源碼學習之keep-alive原理

大部分的Vue應用都採用spa模式開發,從而達到一次加載,全站使用的目的,可以極大地提高應用的用戶體驗。而spa應用的原理其實就是動態的把目標頁面的代碼替換到路由組件內,從而實現路由切換的目的。那麼,問題來了,加入我有頁面A、頁面B兩個頁面,頁面A中有一堆表單,用戶填了一半,然後切換到B頁面去看一個消息,看完想要回到頁面A繼續填寫表單,如果不經任何處理的話,用戶回到頁面A的結果只有一個,自己辛辛苦苦填了老半天的表單數據都被清空了,又得重新填寫。

顯然,這是一個極差的用戶體驗,不過別擔心,Vue已經爲我們考慮了這個問題,它已經爲我們提供了一個內置組件keep-alive組件,只要按照要求使用keep-alive組件,當你從頁面A切換到頁面B時,keep-alive會幫你吧頁面A已經輸入的一些數據緩存下來,當你再從頁面B回到頁面A時,表單的數據便可以自動回填,從而讓用戶可以繼續自己未完成的表單填寫。

那麼,keep-alive組件究竟是如何工作的呢?我們來一起看看吧。

//// 節選自Vue源碼中的src/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 () {
    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: 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
      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
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode)
        }
      }

      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])
  }

從Vue源碼可以看出,當頁面組件觸發了destroy生命週期時,keep-alive會將當前組件緩存到一個緩存對象當中,然後才進行頁面跳轉,當頁面重新切換回頁面A時,keep-alive會先看看緩存中是否存在當前組件的緩存數據,如果存在,便會把數據重新回填至該組件中,由於頁面上的表單都採用雙向綁定,組件中的初始值被填充爲緩存的值時,表單自然也會恢復回頁面跳轉出去前的樣子,這樣就實現了讓頁面組件緩存與恢復緩存數據的邏輯了

PS:以上爲本人在學習Vue源碼時個人的學習感想與記錄,如有不妥,歡迎指正。

發佈了24 篇原創文章 · 獲贊 12 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章