91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue?keep-alive的實現原理是什么

發布時間:2022-04-15 17:28:06 來源:億速云 閱讀:233 作者:zzz 欄目:開發技術

這篇“Vue keep-alive的實現原理是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Vue keep-alive的實現原理是什么”文章吧。

keep-alive的實現原理

使用vue的時候,想必大家都是用過keep-alive,其作用就是緩存頁面以及其狀態。使用了這么久vue只知道如何使用但不明白其中原理,昨天翻看實現代碼,這里做個筆記。

這里以vue3為例

整個組件的源碼為:

const KeepAliveImpl = {
  name: `KeepAlive`,
 
  // Marker for special handling inside the renderer. We are not using a ===
  // check directly on KeepAlive in the renderer, because importing it directly
  // would prevent it from being tree-shaken.
  __isKeepAlive: true,
 
  props: {
    include: [String, RegExp, Array],
    exclude: [String, RegExp, Array],
    max: [String, Number]
  },
 
  setup(props: KeepAliveProps, { slots }: SetupContext) {
    const cache: Cache = new Map()
    const keys: Keys = new Set()
    let current: VNode | null = null
 
    const instance = getCurrentInstance()!
    // console.log('instance',instance)
    // KeepAlive communicates with the instantiated renderer via the "sink"
    // where the renderer passes in platform-specific functions, and the
    // KeepAlive instance exposes activate/deactivate implementations.
    // The whole point of this is to avoid importing KeepAlive directly in the
    // renderer to facilitate tree-shaking.
    const sink = instance.sink as KeepAliveSink
    const {
      renderer: {
        move,
        unmount: _unmount,
        options: { createElement }
      },
      parentSuspense
    } = sink
    const storageContainer = createElement('div')
    // console.log('sink',sink)
    sink.activate = (vnode, container, anchor) => {
      move(vnode, container, anchor, MoveType.ENTER, parentSuspense)
      queuePostRenderEffect(() => {
        const component = vnode.component!
        component.isDeactivated = false
        if (component.a !== null) {
          invokeHooks(component.a)
        }
      }, parentSuspense)
    }
 
    sink.deactivate = (vnode: VNode) => {
      move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense)
      queuePostRenderEffect(() => {
        const component = vnode.component!
        if (component.da !== null) {
          invokeHooks(component.da)
        }
        component.isDeactivated = true
      }, parentSuspense)
    }
 
    function unmount(vnode: VNode) {
      // reset the shapeFlag so it can be properly unmounted
      vnode.shapeFlag = ShapeFlags.STATEFUL_COMPONENT
      _unmount(vnode, instance, parentSuspense)
    }
 
    function pruneCache(filter?: (name: string) => boolean) {
      cache.forEach((vnode, key) => {
        const name = getName(vnode.type as Component)
        if (name && (!filter || !filter(name))) {
          pruneCacheEntry(key)
        }
      })
    }
 
    function pruneCacheEntry(key: CacheKey) {
      const cached = cache.get(key) as VNode
      if (!current || cached.type !== current.type) {
        unmount(cached)
      } else if (current) {
        // current active instance should no longer be kept-alive.
        // we can't unmount it now but it might be later, so reset its flag now.
        current.shapeFlag = ShapeFlags.STATEFUL_COMPONENT
      }
      cache.delete(key)
      keys.delete(key)
    }
 
    watch(
      () => [props.include, props.exclude],
      ([include, exclude]) => {
        include && pruneCache(name => matches(include, name))
        exclude && pruneCache(name => matches(exclude, name))
      },
      { lazy: true }
    )
 
    onBeforeUnmount(() => {
      cache.forEach(unmount)
    })
 
    return () => {
      if (!slots.default) {
        return null
      }
 
      const children = slots.default()
      let vnode = children[0]
      if (children.length > 1) {
        if (__DEV__) {
          warn(`KeepAlive should contain exactly one component child.`)
        }
        current = null
        return children
      } else if (
        !isVNode(vnode) ||
        !(vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT)
      ) {
        current = null
        return vnode
      }
 
      const comp = vnode.type as Component
      const name = getName(comp)
      const { include, exclude, max } = props
 
      if (
        (include && (!name || !matches(include, name))) ||
        (exclude && name && matches(exclude, name))
      ) {
        return vnode
      }
 
      const key = vnode.key == null ? comp : vnode.key
      const cached = cache.get(key)
 
      // clone vnode if it's reused because we are going to mutate it
      if (vnode.el) {
        vnode = cloneVNode(vnode)
      }
      cache.set(key, vnode)
      if (cached) {
        // copy over mounted state
        vnode.el = cached.el
        vnode.anchor = cached.anchor
        vnode.component = cached.component
        if (vnode.transition) {
          // recursively update transition hooks on subTree
          setTransitionHooks(vnode, vnode.transition!)
        }
        // avoid vnode being mounted as fresh
        vnode.shapeFlag |= ShapeFlags.COMPONENT_KEPT_ALIVE
        // make this key the freshest
        keys.delete(key)
        keys.add(key) 
      } else {
        keys.add(key)
        // prune oldest entry
        if (max && keys.size > parseInt(max as string, 10)) { 
          pruneCacheEntry(Array.from(keys)[0])
        }
      }
      // avoid vnode being unmounted
      vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
      current = vnode
      return vnode
    }
  }
}

很容易看出keep-alive其實就是vue自己封裝的一個組件,和普通組件一樣。

再講keep-alive組件前先了解下vue組件的整個渲染

大致流程如下

Vue?keep-alive的實現原理是什么

keep-alive生命周期

組件掛載:

調用setupStatefulComponent函數觸發組件setup方法,其中組件的setup方法核心代碼其實就幾行:

return () => {
    const children = slots.default()
    let vnode = children[0]
    cache.set(key, vnode)
 
    if (cached) {
      vnode.el = cached.el
      vnode.anchor = cached.anchor
      vnode.component = cached.component
      vnode.shapeFlag |= ShapeFlags.COMPONENT_KEPT_ALIVE
      keys.delete(key)
      keys.add(key) 
    } else {
      keys.add(key)
    }
    return vnode
}

主要邏輯為三:

1.確認需要渲染的slot、

2.將其狀態置入緩存或讀取已存在的緩存、

3.返回slot對應的vnode,緊接著調用setupRenderEffect,渲染出dom。

組件更新(slot變化):

當slot變化后,首先會調用keep-alive組件的render即setup的返回函數,邏輯見上面setup方法。緊接著當某個slot卸載時,會調用deactivate函數,當某個slot重新掛載時,則會調用activate函數,核心代碼如下:

const storageContainer = createElement('div')
sink.activate = (vnode, container, anchor) => {
      move(vnode, container, anchor, MoveType.ENTER, parentSuspense)
      queuePostRenderEffect(() => {
        const component = vnode.component!
        component.isDeactivated = false
        if (component.a !== null) {
          invokeHooks(component.a)
        }
      }, parentSuspense)
    }
 
    sink.deactivate = (vnode: VNode) => {
      move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense)
      queuePostRenderEffect(() => {
        const component = vnode.component!
        if (component.da !== null) {
          invokeHooks(component.da)
        }
        component.isDeactivated = true
      }, parentSuspense)
    }

邏輯也很簡單,當組件卸載時,將其移入緩存的dom節點中,調用slot的deactivate生命周期,當組件重新掛載時候,將其移入至掛載的dom節點中。

總結來說,keep-alive實現原理就是將對應的狀態放入一個cache對象中,對應的dom節點放入緩存dom中,當下次再次需要渲染時,從對象中獲取狀態,從緩存dom中移出至掛載dom節點中。

keep-alive的使用總結

在平常開發中,有些組件只需要加載一次,后面的數據將不存在變化,亦或者是組件需要緩存狀態,滾動條位置等,這個時候,keep-alive的用處就立刻凸顯出來了。

1.App.vue中使用keep-alive

include表示需要緩存的頁面,exclude表示不需要緩存的頁面,你可以只設置其中一個即可,但兩個同時設置的時候,切記exclude優先級高于include,例如a組件在exclude中和include中都存在,那么,a組件是不會被緩存的

<template>
    <div id="app">
      <keep-alive :include="whiteList" :exclude="blackList">
        <router-view  v-if="isRouterAlive" ></router-view>
      </keep-alive>
    </div>
</template>
<script>
export default {
    name: 'App',
    data(){
      return{
          isRouterAlive:true,
          whiteList:['styleLibrary','OrderList','SalesData'],
          blackList:['Footer'],
          personShow:false,
      }
    },
}
</script>

2.App.vue中配合router進行使用

<template>
    <div id="app">
  <keep-alive>
    <router-view v-if="$route.meta.keepAlive"></router-view>    <!--緩存組件-->
  </keep-alive>
  <router-view v-if="!$route.meta.keepAlive"></router-view>      <!--非緩存組件-->
    </div>
</template>

將需要緩存的組件的$route.meta中的keepAlive設置為true,反之為false

 {
      path:'/login',
      name:'login',
      component:resolve=>require(['@/pages/login'],resolve),
      meta:{
        keepAlive:true,
        title:'登錄',
        savedPosition:true,
      }
    },

以上就是關于“Vue keep-alive的實現原理是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

湖南省| 安吉县| 江川县| 烟台市| 南昌县| 平定县| 乐都县| 盐池县| 革吉县| 宜黄县| 阿鲁科尔沁旗| 焦作市| 铅山县| 林芝县| 安宁市| 松原市| 绿春县| 蓬溪县| 阳原县| 庄浪县| 五常市| 和林格尔县| 茌平县| 浏阳市| 缙云县| 乌兰浩特市| 滁州市| 闻喜县| 阳曲县| 合水县| 淮滨县| 顺昌县| 娱乐| 陇川县| 常州市| 兴隆县| 漾濞| 监利县| 宁城县| 太仓市| 星子县|