亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Vue3中對(duì)VDOM的改進(jìn)

 更新時(shí)間:2020年04月23日 16:40:45   作者:LhrAlander  
這篇文章主要介紹了詳解Vue3中對(duì)VDOM的改進(jìn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

vue-next 對(duì)virtual dom的patch更新做了一系列的優(yōu)化,從編譯時(shí)加入了 block 以減少 vdom 之間的對(duì)比次數(shù),另外還有 hoisted 的操作減少了內(nèi)存的開(kāi)銷(xiāo)。本文寫(xiě)給自己看,做個(gè)知識(shí)點(diǎn)記錄,如有錯(cuò)誤,還請(qǐng)不吝賜教。

VDOM

VDOM的概念簡(jiǎn)單來(lái)說(shuō)就是用js對(duì)象來(lái)模擬真實(shí)DOM樹(shù)。由于MV**的架構(gòu),真實(shí)DOM樹(shù)應(yīng)該隨著數(shù)據(jù)(Vue2.x中的data)的改變而發(fā)生改變,這些改變可能是以下幾個(gè)方面:

  • v-if
  • v-for
  • 動(dòng)態(tài)的props(如:class,@click)
  • 子節(jié)點(diǎn)的改變
  • 等等

Vue框架要做的其實(shí)很單一:在用戶(hù)改變數(shù)據(jù)時(shí),正確更新DOM樹(shù),做法就是其核心的VDOM的patch和diff算法。

Vue2.x中的做法

在Vue2.x中,當(dāng)數(shù)據(jù)改變后就要對(duì)所有的節(jié)點(diǎn)進(jìn)行patch和diff操作。如以下DOM結(jié)構(gòu):

<div>
 <span class="header">I'm header</span>
 <ul>
  <li>第一個(gè)靜態(tài)li</li>
  <li v-for="item in mutableItems" :key="item.key"> {{ item.desc }}</li>
 </ul>
</div>

在第一次mount節(jié)點(diǎn)的時(shí)候會(huì)去生成真實(shí)的DOM,此后如果

mutableItems.push({
 key: 'asdf',
 desc: 'a new li item'
})

預(yù)期的結(jié)果是頁(yè)面出現(xiàn)新的一個(gè)li元素,內(nèi)容就是 a new li item,Vue2.x中是通過(guò)patch時(shí)對(duì) ul 元素對(duì)應(yīng)的 vnode 的 children 來(lái)進(jìn)行 diff 操作,具體操作在此不深究,但是該操作是需要比較所有的 li 對(duì)應(yīng)的 vnode 的。

不足

正是由于2.x版本中的diff操作需要遍歷所有元素,本例中包括了 span 和 第一個(gè)li元素,但是這兩個(gè)元素是靜態(tài)的,不需要被比較的,不論數(shù)據(jù)怎么變,靜態(tài)元素都不會(huì)再更改了。vue-next在編譯時(shí)對(duì)這種操作做了優(yōu)化,即 Block。

Block

入上述模板,在vue-next中生成的渲染函數(shù)為:

const _Vue = Vue
const { createVNode: _createVNode } = _Vue

const _hoisted_1 = _createVNode("span", { class: "header" }, "I'm header", -1 /* HOISTED */)
const _hoisted_2 = _createVNode("li", null, "第一個(gè)靜態(tài)li", -1 /* HOISTED */)

return function render(_ctx, _cache) {
 with (_ctx) {
  const { createVNode: _createVNode, renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, toDisplayString: _toDisplayString } = _Vue

  return (_openBlock(), _createBlock(_Fragment, null, [
   _hoisted_1,
   _createVNode("ul", null, [
    _hoisted_2,
    (_openBlock(true), _createBlock(_Fragment, null, _renderList(state.mutableItems, (item) => {
     return (_openBlock(), _createBlock("li", { key: item.key }, _toDisplayString(item.desc), 1 /* TEXT */))
    }), 128 /* KEYED_FRAGMENT */))
   ])
  ], 64 /* STABLE_FRAGMENT */))
 }
}

我們可以看到調(diào)用了 openBlock 和 createBlock 方法,這兩個(gè)方法的代碼實(shí)現(xiàn)也很簡(jiǎn)單:

const blockStack: (VNode[] | null)[] = []
let currentBlock: VNode[] | null = null
let shouldTrack = 1
// openBlock
export function openBlock(disableTracking = false) {
 blockStack.push((currentBlock = disableTracking ? null : []))
}
export function createBlock(
 type: VNodeTypes | ClassComponent,
 props?: { [key: string]: any } | null,
 children?: any,
 patchFlag?: number,
 dynamicProps?: string[]
): VNode {
 // avoid a block with patchFlag tracking itself
 shouldTrack--
 const vnode = createVNode(type, props, children, patchFlag, dynamicProps)
 shouldTrack++
 // save current block children on the block vnode
 vnode.dynamicChildren = currentBlock || EMPTY_ARR
 // close block
 blockStack.pop()
 currentBlock = blockStack[blockStack.length - 1] || null
 // a block is always going to be patched, so track it as a child of its
 // parent block
 if (currentBlock) {
  currentBlock.push(vnode)
 }
 return vnode
}

更加詳細(xì)的注釋還請(qǐng)看源代碼中的注釋?zhuān)瑢?xiě)的十分詳盡,便于理解。這里面 openBlock 就是初始化一個(gè)塊,createBlock 就是對(duì)當(dāng)前編譯的內(nèi)容生成一個(gè)塊,這里面的這一行代碼:vnode.dynamicChildren = currentBlock || EMPTY_ARR 就是在收集動(dòng)態(tài)的子節(jié)點(diǎn),我們可以再看一下編譯時(shí)運(yùn)行的函數(shù):

// createVNode
function _createVNode(
 type: VNodeTypes | ClassComponent,
 props: (Data & VNodeProps) | null = null,
 children: unknown = null,
 patchFlag: number = 0,
 dynamicProps: string[] | null = null
) {
 /**
  * 一系列代碼
 **/

 // presence of a patch flag indicates this node needs patching on updates.
 // component nodes also should always be patched, because even if the
 // component doesn't need to update, it needs to persist the instance on to
 // the next vnode so that it can be properly unmounted later.
 if (
  shouldTrack > 0 &&
  currentBlock &&
  // the EVENTS flag is only for hydration and if it is the only flag, the
  // vnode should not be considered dynamic due to handler caching.
  patchFlag !== PatchFlags.HYDRATE_EVENTS &&
  (patchFlag > 0 ||
   shapeFlag & ShapeFlags.SUSPENSE ||
   shapeFlag & ShapeFlags.STATEFUL_COMPONENT ||
   shapeFlag & ShapeFlags.FUNCTIONAL_COMPONENT)
 ) {
  currentBlock.push(vnode)
 }
}

上述函數(shù)是在模板編譯成ast之后調(diào)用的生成VNode的函數(shù),所以有patchFlag這個(gè)標(biāo)志,如果是動(dòng)態(tài)的節(jié)點(diǎn),并且此時(shí)是開(kāi)啟了Block的話(huà),就會(huì)將節(jié)點(diǎn)塞入Block中,這樣 createBlock返回的 VNode 中就會(huì)有 dynamicChildren 了。

到此為止,通過(guò)本文中案例經(jīng)過(guò)模板編譯和render函數(shù)運(yùn)行后并經(jīng)過(guò)了優(yōu)化以后生成了如下結(jié)構(gòu)的vnode:

const result = {
 type: Symbol(Fragment),
 patchFlag: 64,
 children: [
  { type: 'span', patchFlag: -1, ...},
  {
   type: 'ul',
   patchFlag: 0,
   children: [
    { type: 'li', patchFlag: -1, ...},
    {
     type: Symbol(Fragment),
     children: [
      { type: 'li', patchFlag: 1 ...},
      { type: 'li', patchFlag: 1 ...}
     ]
    }
   ]
  }
 ],
 dynamicChildren: [
  {
   type: Symbol(Fragment),
   patchFlag: 128,
   children: [
    { type: 'li', patchFlag: 1 ...},
    { type: 'li', patchFlag: 1 ...}
   ]
  }
 ]
}

以上的 result 不完整,但是我們暫時(shí)只關(guān)心這些屬性??梢钥匆?jiàn) result.children 的第一個(gè)元素是span,patchFlag=-1,且 result 有一個(gè) dynamicChildren 數(shù)組,里面只包含了兩個(gè)動(dòng)態(tài)的 li,后續(xù)如果變動(dòng)了數(shù)據(jù),那么新的 vnode.dynamicChildren 會(huì)有第三個(gè) li 元素。

patch

patch部分其實(shí)也沒(méi)差多少,就是根據(jù)vnode的type執(zhí)行不同的patch操作:

function patchElement(n1, n2) {
 let { dynamicChildren } = n2
 // 一系列操作

 if (dynamicChildren) {
  patchBlockChildren (
   n1.dynamicChildren!,
   dynamicChildren,
   el,
   parentComponent,
   parentSuspense,
   areChildrenSVG
  )
 } else if (!optimized) {
  // full diff
  patchChildren(
   n1,
   n2,
   el,
   null,
   parentComponent,
   parentSuspense,
   areChildrenSVG
  )
 }
}

可以看見(jiàn),如果有了 dynamicChildren 那么vue2.x版本中的diff操作就被替換成了 patchBlockChildren() 且參數(shù)只有 dynamicChildren,就是靜態(tài)的不做diff操作了,而如果vue-next的patch中沒(méi)有 dynamicChildren,則進(jìn)行完整的diff操作,入注釋寫(xiě)的 full diff 的后續(xù)代碼。

結(jié)尾

本文沒(méi)有深入講解代碼的實(shí)現(xiàn)層面,一是因?yàn)樽约簩?shí)力不濟(jì)還在閱讀源碼當(dāng)中,二是我個(gè)人認(rèn)為閱讀源碼不可鉆牛角尖,從大局入眼,再徐徐圖之,先明白了各個(gè)部分的作用后帶著思考去閱讀源碼能收獲到的應(yīng)該更多一些。

到此這篇關(guān)于詳解Vue3中對(duì)VDOM的改進(jìn)的文章就介紹到這了,更多相關(guān)Vue3 VDOM內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue自定義指令添加跟隨鼠標(biāo)光標(biāo)提示框v-tooltip方式

    vue自定義指令添加跟隨鼠標(biāo)光標(biāo)提示框v-tooltip方式

    這篇文章主要介紹了vue自定義指令添加跟隨鼠標(biāo)光標(biāo)提示框v-tooltip方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Vue3 使用Vuex和router的注意事項(xiàng)及操作方法

    Vue3 使用Vuex和router的注意事項(xiàng)及操作方法

    在vue2中 使用的?this.$route?和?this.$router?this.$store的使用在vue3中完全適用,這篇文章主要介紹了Vue3 使用Vuex和router的注意事項(xiàng)及操作方法,需要的朋友可以參考下
    2022-12-12
  • vue引用public文件夾中文件的多種方式

    vue引用public文件夾中文件的多種方式

    由于一些演示需要對(duì)一些簡(jiǎn)單頁(yè)面進(jìn)行配置,由于打包build后的vue項(xiàng)目基本已經(jīng)看不出原樣,因此需要?jiǎng)?chuàng)建一個(gè)文件,并在打包的時(shí)候不會(huì)進(jìn)行編譯,所以文件放在public,這篇文章主要給大家介紹了關(guān)于vue引用public文件夾中文件的多種方式,需要的朋友可以參考下
    2024-02-02
  • Vue完整項(xiàng)目構(gòu)建(進(jìn)階篇)

    Vue完整項(xiàng)目構(gòu)建(進(jìn)階篇)

    這篇文章主要介紹了Vue完整項(xiàng)目構(gòu)建(進(jìn)階篇)的相關(guān)資料,需要的朋友可以參考下
    2018-02-02
  • Vue中的$set的使用實(shí)例代碼

    Vue中的$set的使用實(shí)例代碼

    這篇文章主要介紹了Vue中的$set的使用,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-10-10
  • 淺談vue.js導(dǎo)入css庫(kù)(elementUi)的方法

    淺談vue.js導(dǎo)入css庫(kù)(elementUi)的方法

    下面小編就為大家分享一篇淺談vue.js導(dǎo)入css庫(kù)(elementUi)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • vue3輸入框生成的時(shí)候如何自動(dòng)獲取焦點(diǎn)詳解

    vue3輸入框生成的時(shí)候如何自動(dòng)獲取焦點(diǎn)詳解

    記錄一下自己最近開(kāi)發(fā)vue3.0的小小問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于vue3輸入框生成的時(shí)候如何自動(dòng)獲取焦點(diǎn)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • 詳解VUE調(diào)用本地json的使用方法

    詳解VUE調(diào)用本地json的使用方法

    這篇文章主要介紹了VUE調(diào)用本地json的使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • 解決Vue數(shù)據(jù)更新了但頁(yè)面沒(méi)有更新的問(wèn)題

    解決Vue數(shù)據(jù)更新了但頁(yè)面沒(méi)有更新的問(wèn)題

    在vue項(xiàng)目中,有些我們會(huì)遇到修改完數(shù)據(jù),但是視圖卻沒(méi)有更新的情況,具體的場(chǎng)景不一樣,解決問(wèn)題的方法也不一樣,在網(wǎng)上看了很多文章,在此總結(jié)匯總一下,需要的朋友可以參考下
    2023-08-08
  • 詳解vue+css3做交互特效的方法

    詳解vue+css3做交互特效的方法

    本篇文章主要介紹了詳解vue+css3做交互特效的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11

最新評(píng)論