成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Vue中的KeepAlive組件怎么使用

這篇文章主要介紹“Vue中的KeepAlive組件怎么使用”,在日常操作中,相信很多人在Vue中的KeepAlive組件怎么使用問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Vue中的KeepAlive組件怎么使用”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

順平ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書(shū)未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)建站的ssl證書(shū)銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書(shū)合作)期待與您的合作!

KeepAlive 是什么

<KeepAlive> 是一個(gè)內(nèi)置組件,它的功能是在多個(gè)組件間動(dòng)態(tài)切換時(shí)緩存被移除的組件實(shí)例。

KeepAlive 功能

KeepAlive 一詞借鑒于 HTTP 協(xié)議,在 HTTP 協(xié)議里面 KeepAlive 又稱持久連接,作用是允許多個(gè)請(qǐng)求/響應(yīng)共用同一個(gè) HTTP 連接,解決了頻繁的銷毀和創(chuàng)建 HTTP 連接帶來(lái)的額外性能開(kāi)銷。而同理 Vue 里的 KeepAlive 組件也是為了避免一個(gè)組件被頻繁的銷毀/重建,避免了性能上的開(kāi)銷。

// App.vue
<Test :msg="curTab" v-if="curTab === 'Test'"></Test>
<HelloWorld :msg="curTab" v-if="curTab === 'HelloWorld'"></HelloWorld>
<div @click="toggle">toggle</div>

上述代碼可以看到,如果我們頻繁點(diǎn)擊 toggle 時(shí)會(huì)頻繁的渲染 Test/HelloWorld 組件,當(dāng)用戶頻繁的點(diǎn)擊時(shí) Test 組件需要頻繁的銷毀/渲染,這就造成很大的渲染性能損失。

所以為了解決這種性能開(kāi)銷,你需要知道是時(shí)候使用 KeepAlive 組件。

<KeepAlive>
  <component :is="curTab === 'Test' ? Test : HelloWorld" :msg="curTab"></component>
</KeepAlive>
<div @click="toggle">toggle</div>

Vue中的KeepAlive組件怎么使用

可以看這個(gè)錄屏,在首次加載后再次頻繁的切換并沒(méi)有重新銷毀與掛載,而僅僅是將組件進(jìn)行了失活(而不是銷毀),渲染時(shí)只需要重新激活就可以,而不需重新掛載,如果要渲染的組件很大,那就能有不錯(cuò)的性能優(yōu)化。

想要體驗(yàn)的話可以去看看這個(gè)例子?官方demo,其中數(shù)據(jù)會(huì)被緩存這個(gè)也需要在開(kāi)發(fā)使用中去注意到的

如何實(shí)現(xiàn)

實(shí)現(xiàn)原理其實(shí)很簡(jiǎn)單,其實(shí)就是緩存管理和特定的銷毀和渲染邏輯,使得它不同于其他組件。

KeepAlive 組件在卸載組件時(shí)并不能真的將其卸載,而是將其放到一個(gè)隱藏的容器里面,當(dāng)被激活時(shí)再?gòu)碾[藏的容器中拿出來(lái)掛載到真正的 dom 上就行,這也就對(duì)應(yīng)了 KeepAlive 的兩個(gè)獨(dú)特的生命周期activateddeactivated。

Vue中的KeepAlive組件怎么使用

先來(lái)簡(jiǎn)單了解下組件的掛載過(guò)程

Vue中的KeepAlive組件怎么使用

所以在 KeepAlive 內(nèi)的子組件在 mount 和 unmount 的時(shí)候會(huì)執(zhí)行特定的渲染邏輯,從而不會(huì)去走掛載和銷毀邏輯

具體實(shí)現(xiàn)(實(shí)現(xiàn)一個(gè)小而簡(jiǎn)單的 KeepAlive)

  • KeepAlive 組件的屬性

const KeepAliveImpl: ComponentOptions = {
  name: "KeepAlive",
  // 標(biāo)識(shí)這是一個(gè) KeepAlive 組件
  __isKeepAlive: true,
  // props
  props: {
    exclude: [String, Array, RegExp],
    include: [String, Array, RegExp],
    max: [String, Number]
  }
 }
 
 // isKeepAlive
 export const isKeepAlive = (vnode: VNode): boolean =>
  (vnode.type as any).__isKeepAlive

  • KeepAlive 組件的 setup 邏輯以及渲染邏輯(重點(diǎn)看)

// setup 接著上面的代碼
// 獲取到當(dāng)前 KeepAlive 組件實(shí)例
const instance = getCurrentInstance()! as any;
// 拿到 ctx
const sharedContext = instance.ctx as KeepAliveContext;
// cache 緩存
// key: vnode.key | vnode.type value: vnode
const cache: Cache = new Map()
// 需要拿到某些的 renderer 操作函數(shù),需要自己特定執(zhí)行渲染和卸載邏輯
const { renderer: { p: patch, m: move, um: _unmount, o: { createElement } } } = sharedContext
// 隱藏的容器,用來(lái)存儲(chǔ)需要隱藏的 dom
const storeageContainer = createElement('div')

// 存儲(chǔ)當(dāng)前的子組件的緩存 key
let pendingKey: CacheKey | null = null

sharedContext.activate = (vnode, container, anchor) => {
  // KeepAlive 下組件激活時(shí)執(zhí)行的 move 邏輯
  move(vnode, container, anchor, 0 /* ENTER */)
}

sharedContext.deactivate = (vnode) => {
  // KeepAlive 下組件失活時(shí)執(zhí)行的 move 邏輯
  move(vnode, storeageContainer, null, 1 /* LEAVE */)
}

return () => {
  // 沒(méi)有子組件
  if (!slots.default) {
    return null;
  }
  const children = slots.default() as VNode[];
  const rawNode = children[0];
  let vnode = rawNode;
  const comp = vnode.type as ConcreteComponent;
  const name = comp.displayName || comp.name
  const { include, exclude } = props;
  // 沒(méi)有命中的情況
  if (
    (include && (!name || !matches(include, name))) ||
    (exclude && name && matches(exclude, name))
  ) {
    // 直接渲染子組件
    return rawNode;
  }
  // 獲取子組件的 vnode key
  const key = vnode.key == null ? comp : vnode.key;
  // 獲取子組件緩存的 vnode
  const cachedVNode = cache.get(key);

  pendingKey = key;
  // 命中緩存
  if (cachedVNode) {
    vnode.el = cachedVNode.el;
    // 繼承組件實(shí)例
    vnode.component = cachedVNode.component;
    // 在 vnode 上更新 shapeFlag,標(biāo)記為 COMPONENT_KEPT_ALIVE 屬性,防止渲染器重新掛載
    vnode.shapeFlag |= ShapeFlags.COMPONENT_KEPT_ALIVE
  } else {
    // 沒(méi)命中將其緩存
    cache.set(pendingKey, vnode)
  }
  // 在 vnode 上更新 shapeFlag,標(biāo)記為 COMPONENT_SHOULD_KEEP_ALIVE 屬性,防止渲染器將組件卸載了
  vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
  // 渲染組件 vnode
  return vnode;
}

  • KeepAlive組件 mount 時(shí)掛載 renderer 到 ctx 上

在 KeepAlive 組件內(nèi)會(huì)從 sharedContext 上的 renderer 上拿到一些方法比如 move、createElement 等

function mountComponent() {
 // ...
 if (isKeepAlive(initialVNode)) {
    ;(instance.ctx as KeepAliveContext).renderer = internals
  }
}

  • 子組件執(zhí)行特定的銷毀和渲染邏輯

首先從上面可以看到,在渲染 KeepAlive 組件時(shí)會(huì)對(duì)其子組件的 vnode 上增加對(duì)應(yīng)的 shapeFlag 標(biāo)志

比如COMPONENT_KEPT_ALIVE標(biāo)志,組件掛載的時(shí)候告訴渲染器這個(gè)不需要 mount 而需要特殊處理

const processComponent = (
    n1: VNode | null,
    n2: VNode,
    container: RendererElement,
    anchor: RendererNode | null,
  ) => {
    if (n1 == null) {
      // 在 KeepAlive 組件渲染時(shí)會(huì)對(duì)子組件增加 COMPONENT_KEPT_ALIVE 標(biāo)志
      // 掛載子組件時(shí)會(huì)判斷是否 COMPONENT_KEPT_ALIVE ,如果是不會(huì)調(diào)用 mountComponent 而是直接執(zhí)行 activate 方法
      if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
        ;(parentComponent!.ctx as KeepAliveContext).activate(
          n2,
          container,
          anchor
        )
      }
      // ...
    }
  }

同理COMPONENT_SHOULD_KEEP_ALIVE標(biāo)志也是用來(lái)在組件卸載的時(shí)候告訴渲染器這個(gè)不需要 unmount 而需要特殊處理。

const unmount: UnmountFn = (vnode) => {
  // ...
  // 在 KeepAlive 組件渲染時(shí)會(huì)對(duì)子組件增加 COMPONENT_SHOULD_KEEP_ALIVE 標(biāo)志
  // 然后在子組件卸載時(shí)并不會(huì)真實(shí)的卸載而是調(diào)用 KeepAlive 的 deactivate 方法
  if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
    ;(parentComponent!.ctx as KeepAliveContext).deactivate(vnode)
    return
  }
}

  • 如何掛載activateddeactivated生命周期(生命周期相關(guān)可以不用重點(diǎn)看)

首先這兩個(gè)生命周期是在 KeepAlive 組件內(nèi)獨(dú)特聲明的,是直接導(dǎo)出使用的。

export function onActivated(
  hook: Function,
  target?: ComponentInternalInstance | null
) {
  // 注冊(cè) activated 的回調(diào)函數(shù)到當(dāng)前的 instance 的鉤子函數(shù)上
  registerKeepAliveHook(hook, LifecycleHooks.ACTIVATED, target)
}
export function onDeactivated(
  hook: Function,
  target?: ComponentInternalInstance | null
) {
  // 注冊(cè) deactivated 的回調(diào)函數(shù)到當(dāng)前的 instance 的鉤子函數(shù)上
  registerKeepAliveHook(hook, LifecycleHooks.DEACTIVATED, target)
}

然后因?yàn)檫@兩個(gè)生命周期會(huì)注冊(cè)在 setup 里面,所以只要執(zhí)行 setup 就會(huì)將兩個(gè)生命周期的回調(diào)函數(shù)注冊(cè)到當(dāng)前的 instance 實(shí)例上

// renderer.ts
// mount 函數(shù)邏輯
const mountComponent = (initialVNode,
  container,
  anchor,
  parentComponent,
  parentSuspense,
  isSVG,
  optimized
) => {
  // ...
  const instance: ComponentInternalInstance =
    compatMountInstance ||
    (initialVNode.component = createComponentInstance(
    initialVNode,
    parentComponent,
    parentSuspense
  ))
  // 執(zhí)行 setup
  setupComponent(instance)
}
// setupcomponent 處理 setup 函數(shù)值
export function setupComponent(
  instance: ComponentInternalInstance,
  isSSR = false
) {
  // ...
  const isStateful = isStatefulComponent(instance)
  // ...
  const setupResult = isStateful
    // setupStatefulComponent 函數(shù)主要功能是設(shè)置當(dāng)前的 instance
    ? setupStatefulComponent(instance, isSSR)
    : undefined
  // ...
}

function setupStatefulComponent(
  instance: ComponentInternalInstance
){
  if (setup) {
    //設(shè)置當(dāng)前實(shí)例
    setCurrentInstance(instance)
    // 執(zhí)行組件內(nèi) setup 函數(shù),執(zhí)行 onActivated 鉤子函數(shù)進(jìn)行回調(diào)函數(shù)收集
    const setupResult = callWithErrorHandling(
      setup,
      instance,
      ErrorCodes.SETUP_FUNCTION,
      [__DEV__ ? shallowReadonly(instance.props) : instance.props, setupContext]
    )
    // currentInstance = null;
    unsetCurrentInstance()
  }
}

最后在執(zhí)行sharedContext.activatesharedContext.deactivate的時(shí)候?qū)⒆?cè)在實(shí)例上的回調(diào)函數(shù)取出來(lái)直接執(zhí)行就OK了,執(zhí)行時(shí)機(jī)在 postRender 之后

sharedContext.activate = (vnode, container, anchor) => {
  // KeepAlive 下組件激活時(shí)執(zhí)行的 move 邏輯
  move(vnode, container, anchor, 0 /* ENTER */)
  // 把回調(diào)推入到 postFlush 的異步任務(wù)隊(duì)列中去執(zhí)行
  queuePostRenderEffect(() => {
    if (instance.a) {
      // a是 activated 鉤子的簡(jiǎn)稱
      invokeArrayFns(instance.a)
    }
  })
}
sharedContext.activate = (vnode, container, anchor) => {
  // KeepAlive 下組件失活時(shí)執(zhí)行的 move 邏輯
  move(vnode, container, anchor, 0 /* ENTER */)
  queuePostRenderEffect(() => {
    if (instance.da) {
      // da是 deactivated 鉤子的簡(jiǎn)稱
      invokeArrayFns(instance.da)
    }
  })
}

export const enum LifecycleHooks {
  // ... 其他生命周期聲明
  DEACTIVATED = 'da',
  ACTIVATED = 'a',
}
export interface ComponentInternalInstance {
// ... 其他生命周期
[LifecycleHooks.ACTIVATED]: Function[]
[LifecycleHooks.DEACTIVATED]: Function[]
}

以下是關(guān)于上述demo如何實(shí)現(xiàn)的簡(jiǎn)化流程圖

Vue中的KeepAlive組件怎么使用

需要注意的知識(shí)點(diǎn)

1、什么時(shí)候緩存

KeepAlive 組件的onMountedonUpdated生命周期時(shí)進(jìn)行緩存

2、什么時(shí)候取消緩存
  • 緩存數(shù)量超過(guò)設(shè)置的 max 時(shí)

  • 監(jiān)聽(tīng) include 和 exclude 修改的時(shí)候,會(huì)讀取緩存中的知進(jìn)行判斷是否需要清除緩存

修剪緩存的時(shí)候也要 unmount(如果該緩存不是當(dāng)前組件)或者 resetShapeFlag 將標(biāo)志為從 KeepAlive 相關(guān) shapeFlag 狀態(tài)重置為 STATEFUL_COMPONENT 狀態(tài)(如果該緩存是當(dāng)前組件,但是被exclude了),當(dāng)然 unmount 函數(shù)內(nèi)包含 resetShapeFlag 操作

3、緩存策略

KeepAlive 組件的緩存策略是 LRU(last recently used)緩存策略

核心思想在于需要把當(dāng)前訪問(wèn)或渲染的組件作為最新一次渲染的組件,并且該組件在緩存修剪過(guò)程中始終是安全的,即不會(huì)被修剪。

4、如何添加到 vue devtools 組件樹(shù)上

sharedContext.activate = (vnode, container, anchor) => {
  // instance 是子組件實(shí)例
  const instance = vnode.component!
  // ...
  // dev環(huán)境下設(shè)置, 自己模擬寫(xiě)的
  devtools.emit('component:added', instance.appContext.app, instance.uid, instance.parent ? instance.parent.uid: undefined, instance)
  // 官方添加
  if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
    // Update components tree
    devtoolsComponentAdded(instance)
  }
}
// 同理 sharedContext.deactivates 上也要添加,不然不會(huì)顯示在組件樹(shù)上

5、緩存的子組件 props 更新處理

當(dāng)子組件有 prop 更新時(shí)是需要重新去 patch 的,所以在 activate 的時(shí)候需要重新執(zhí)行 patch 進(jìn)行子組件更新

sharedContext.activate = (vnode, container, anchor) => {
  // ...
  // props 改變需要重新 patch(update)
  patch(
    instance.vnode,
    vnode,
    container,
    anchor,
    instance,
    parentSuspense,
    isSVG,
    vnode.slotScopeIds,
    optimized
  )
}

到此,關(guān)于“Vue中的KeepAlive組件怎么使用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

分享文章:Vue中的KeepAlive組件怎么使用
轉(zhuǎn)載源于:http://jinyejixie.com/article2/gdpeic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、虛擬主機(jī)、網(wǎng)站維護(hù)品牌網(wǎng)站建設(shè)、網(wǎng)站策劃商城網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)
马关县| 名山县| 静宁县| 宜兰市| 焦作市| 济阳县| 辽中县| 海淀区| 两当县| 鲁甸县| 北流市| 南京市| 鄂托克旗| 南京市| 海兴县| 桑日县| 樟树市| 花莲市| 河池市| 长春市| 金乡县| 伽师县| 平乡县| 六安市| 台前县| 惠来县| 什邡市| 水城县| 山阳县| 左贡县| 博湖县| 正宁县| 武胜县| 平远县| 襄樊市| 金寨县| 新河县| 临泽县| 新安县| 七台河市| 台南县|