日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

vue 虛擬DOM快速入門

瀏覽:37日期:2022-09-30 15:41:37
虛擬 DOM什么是虛擬 dom

dom 是文檔對象模型,以節(jié)點(diǎn)樹的形式來表現(xiàn)文檔。

虛擬 dom 不是真正意義上的 dom。而是一個(gè) javascript 對象。

正常的 dom 節(jié)點(diǎn)在 html 中是這樣表示:

<div class=’testId’> <p>你好</p> <p>歡迎光臨</p></div>

而在虛擬 dom 中大概是這樣:

{ tag: ’div’, attributes:{class: [’testId’] }, children:[// p 元素// p 元素 ]}

我們可以將虛擬 dom 拆分成兩部分進(jìn)行理解:虛擬 + dom。

虛擬: 表示虛擬 dom 不是真正意義上的 dom,而是一個(gè) javascript 對象; dom: 表示虛擬 dom 能以類似節(jié)點(diǎn)樹的形式表示文檔。 虛擬 dom 的作用

現(xiàn)在主流的框架都是聲明式操作 dom 的框架。我們只需要描述狀態(tài)與 dom 之間的映射關(guān)系即可,狀態(tài)到視圖(真實(shí)的 dom)的轉(zhuǎn)換,框架會(huì)幫我們做。

最粗暴的做法是將狀態(tài)渲染成視圖,每次更新狀態(tài),都重新更新整個(gè)視圖。

這種做法的性能可想而知。比較好的想法是:狀態(tài)改變,只更新與狀態(tài)相關(guān)的 dom 節(jié)點(diǎn)。虛擬 dom 只是實(shí)現(xiàn)這個(gè)想法的其中一種方法而已。

具體做法:

狀態(tài) -> 真實(shí) dom(最初) 狀態(tài) -> 虛擬 dom -> 真實(shí) dom(使用虛擬 dom)

狀態(tài)改變,重新生成一份虛擬 dom,將上一份和這一份虛擬 dom 進(jìn)行對比,找出需要更新的部分,更新真實(shí) dom。

vue 中的虛擬 dom

真實(shí)的 dom 是由 節(jié)點(diǎn)(Node)組成,虛擬 dom 則是由虛擬節(jié)點(diǎn)(vNode)組成。

虛擬 dom 在 vue 中主要做兩件事:

提供與真實(shí)節(jié)點(diǎn)(Node)對應(yīng)的虛擬節(jié)點(diǎn)(vNode) 將新的虛擬節(jié)點(diǎn)與舊的虛擬節(jié)點(diǎn)進(jìn)行對比,找出需要差異,然后更新視圖

“虛擬 DOM”是我們對由 Vue 組件樹建立起來的整個(gè) VNode 樹的稱呼 —— vue 官網(wǎng)

vNode什么是 vNode

上文提到,vNode(虛擬節(jié)點(diǎn))對應(yīng)的是真實(shí)節(jié)點(diǎn)(Node)。

vNode 可以理解成節(jié)點(diǎn)描述對象。描述了如何創(chuàng)建真實(shí)的 dom 節(jié)點(diǎn)。

vue.js 中有一個(gè) vNode 類。可以使用它創(chuàng)建不同類型的 vNode 實(shí)例,不同類型的 vNode 對應(yīng)著不同類型的 dom 元素。代碼如下:

export default class VNode { constructor ( tag?: string, data?: VNodeData, children?: ?Array<VNode>, text?: string, elm?: Node, context?: Component, componentOptions?: VNodeComponentOptions, asyncFactory?: Function ) { this.tag = tag this.data = data this.children = children this.text = text this.elm = elm this.ns = undefined this.context = context this.fnContext = undefined this.fnOptions = undefined this.fnScopeId = undefined this.key = data && data.key this.componentOptions = componentOptions this.componentInstance = undefined this.parent = undefined this.raw = false this.isStatic = false this.isRootInsert = true this.isComment = false this.isCloned = false this.isOnce = false this.asyncFactory = asyncFactory this.asyncMeta = undefined this.isAsyncPlaceholder = false } get child (): Component | void { return this.componentInstance }}

從代碼不難看出 vNode 類創(chuàng)建的實(shí)例,本質(zhì)上就是一個(gè)普通的 javascript 對象。

vNode 的類型

前面我們已經(jīng)介紹通過 vNode 類可以創(chuàng)建不同類型的 vNode。而不同類型的 vNode 是由有效屬性區(qū)分。例如 isComment = true 表示注釋節(jié)點(diǎn);isCloned = true 表示克隆節(jié)點(diǎn)等等。

vNode 類型有:注釋節(jié)點(diǎn)、文本節(jié)點(diǎn)、克隆節(jié)點(diǎn)、元素節(jié)點(diǎn)、組件節(jié)點(diǎn)。

以下是注釋節(jié)點(diǎn)、文本節(jié)點(diǎn)和克隆節(jié)點(diǎn)的代碼:

/*注釋節(jié)點(diǎn)有效屬性:{isComment: true, text: ’注釋節(jié)點(diǎn)’}*/export const createEmptyVNode = (text: string = ’’) => { const node = new VNode() node.text = text // 注釋 node.isComment = true return node}/*文本節(jié)點(diǎn)有效屬性:{text: ’文本節(jié)點(diǎn)’}*/export function createTextVNode (val: string | number) { return new VNode(undefined, undefined, undefined, String(val))}// optimized shallow clone// used for static nodes and slot nodes because they may be reused across// 用于靜態(tài)節(jié)點(diǎn)和插槽節(jié)點(diǎn)// multiple renders, cloning them avoids errors when DOM manipulations rely// on their elm reference.// 克隆節(jié)點(diǎn)export function cloneVNode (vnode: VNode): VNode { const cloned = new VNode( vnode.tag, vnode.data, // #7975 // clone children array to avoid mutating original in case of cloning // a child. vnode.children && vnode.children.slice(), vnode.text, vnode.elm, vnode.context, vnode.componentOptions, vnode.asyncFactory ) cloned.ns = vnode.ns cloned.isStatic = vnode.isStatic cloned.key = vnode.key cloned.isComment = vnode.isComment cloned.fnContext = vnode.fnContext cloned.fnOptions = vnode.fnOptions cloned.fnScopeId = vnode.fnScopeId cloned.asyncMeta = vnode.asyncMeta // 標(biāo)記是克隆節(jié)點(diǎn) cloned.isCloned = true return cloned}

克隆節(jié)點(diǎn)其實(shí)就是將現(xiàn)有節(jié)點(diǎn)的所有屬性賦值到新節(jié)點(diǎn)中,最后用 cloned.isCloned = true 標(biāo)記自身是克隆節(jié)點(diǎn)。

元素節(jié)點(diǎn)通常有以下 4 個(gè)屬性:

tag:節(jié)點(diǎn)名稱。例如 div、p data:節(jié)點(diǎn)上的數(shù)據(jù)。例如 class、style children:子節(jié)點(diǎn) context:在組件內(nèi)呈現(xiàn)

組件節(jié)點(diǎn)與元素節(jié)點(diǎn)類似,包含兩個(gè)獨(dú)有的屬性:

componentOptions:組件節(jié)點(diǎn)的選項(xiàng)參數(shù),例如propsData、listeners、children、tag componentInstance:組件的實(shí)例 patch

前面已經(jīng)介紹了虛擬 dom 在 vue 中做的第一件事:提供與真實(shí)節(jié)點(diǎn)(Node)對應(yīng)的虛擬節(jié)點(diǎn)(vNode);接下來介紹第二件事:將新的虛擬節(jié)點(diǎn)與舊的虛擬節(jié)點(diǎn)進(jìn)行對比,找出需要差異,然后更新視圖。

第二件事在 vue 中的實(shí)現(xiàn)叫做 patch,即打補(bǔ)丁、修補(bǔ)的意思。通過對比新舊 vNode,找出差異,然后在現(xiàn)有 dom 的基礎(chǔ)上進(jìn)行修補(bǔ),從而實(shí)現(xiàn)視圖更新。

對比 vNode 找差異是手段,更新視圖才是目的。

而更新視圖無非就是新增節(jié)點(diǎn)、刪除節(jié)點(diǎn)和更新節(jié)點(diǎn)。接下來我們逐一分析什么時(shí)候新增節(jié)點(diǎn)、在哪里新增;什么時(shí)候刪除節(jié)點(diǎn),刪除哪個(gè);什么時(shí)候更新節(jié)點(diǎn),更新哪個(gè);

注:當(dāng) vNode 與 oldVNode 不相同的時(shí)候,以 vNode 為準(zhǔn)。

新增節(jié)點(diǎn)

一種情況是:vNode 存在而 oldVNode 不存在時(shí),需要新增節(jié)點(diǎn)。最典型的是初次渲染,因?yàn)?odlVNode 是不存在的。

另一種情況是 vNode 與 oldVNode 完全不是同一個(gè)節(jié)點(diǎn)。這時(shí)就需要使用 vNode 生成真實(shí)的 dom 節(jié)點(diǎn)并插入到 oldVNode 指向的真實(shí) dom 節(jié)點(diǎn)旁邊。oldVNode 則是一個(gè)被廢棄的節(jié)點(diǎn)。例如下面這種情況:

<div> <p v-if='type === ’A’'> 我是節(jié)點(diǎn)A </p> <span v-else-if='type === ’B’'> 我是與A完全不同的節(jié)點(diǎn)B </span></div>

當(dāng) type 由 A 變?yōu)?B,節(jié)點(diǎn)就會(huì)從 p 變成 span,由于 vNode 與 oldVNode 完全不是同一個(gè)節(jié)點(diǎn),所以需要新增節(jié)點(diǎn)。

刪除節(jié)點(diǎn)

當(dāng)節(jié)點(diǎn)只在 oldVNode 中存在時(shí),直接將其刪除即可。

更新節(jié)點(diǎn)

前面介紹了新增節(jié)點(diǎn)和刪除節(jié)點(diǎn)的場景,發(fā)現(xiàn)它們有一個(gè)共同點(diǎn):vNode 與 oldVNode 完全不相同。

但更常見的場景是 vNode 與 oldVNode 是同一個(gè)節(jié)點(diǎn)。然后我們需要對它們(vNode 與 oldVNode)進(jìn)行一個(gè)更細(xì)致的對比,再對 oldVNode 對應(yīng)的真實(shí)節(jié)點(diǎn)進(jìn)行更新。

對于文本節(jié)點(diǎn),邏輯自然簡單。首先對比新舊 vNode,發(fā)現(xiàn)是同一個(gè)節(jié)點(diǎn),然后將 oldVNode 對應(yīng)的 dom 節(jié)點(diǎn)的文本改成 vNode 中的文本即可。但對于復(fù)雜的 vNode,比如界面中的一顆樹組件,這個(gè)過程就會(huì)變得復(fù)雜。

新增節(jié)點(diǎn) - 源碼分析

思考一下:前面說到 vNode 的類型有:注釋節(jié)點(diǎn)、文本節(jié)點(diǎn)、克隆節(jié)點(diǎn)、元素節(jié)點(diǎn)、組件節(jié)點(diǎn)。請問這幾種類型都會(huì)被創(chuàng)建并插入到 dom 中嗎?

答:只有注釋節(jié)點(diǎn)、文本節(jié)點(diǎn)、元素節(jié)點(diǎn)。因?yàn)?html 只認(rèn)識(shí)這幾種。

由于只有上面三種節(jié)點(diǎn)類型,根據(jù)類型做響應(yīng)的創(chuàng)建,然后插入對應(yīng)的位置即可。

以元素節(jié)點(diǎn)為例,如果 vNode 有 tag 屬性,則說明是元素節(jié)點(diǎn)。則調(diào)用 createElement 方法創(chuàng)建對應(yīng)的節(jié)點(diǎn),接下來就通過 appendChild 方法插入到指定父節(jié)點(diǎn)中。如果父元素已經(jīng)在視圖中,那么把元素插入到它下面將會(huì)自動(dòng)渲染出來;如果 vNode 的 isComment 屬性是 true,則表示注釋節(jié)點(diǎn);都不是則是文本節(jié)點(diǎn);

通常元素里面會(huì)有子節(jié)點(diǎn),所以這里涉及一個(gè)遞歸的過程,也就是將 vNode 中的 children 依次遍歷,創(chuàng)建節(jié)點(diǎn),然后插入到父節(jié)點(diǎn)(父節(jié)點(diǎn)也就是剛剛創(chuàng)建出的 dom 節(jié)點(diǎn))中,一層一層的遞歸進(jìn)行。

請看源碼:

// 創(chuàng)建元素function createElm ( vnode, insertedVnodeQueue, parentElm, refElm, nested, ownerArray, index) { if (isDef(vnode.elm) && isDef(ownerArray)) { // This vnode was used in a previous render! // now it’s used as a new node, overwriting its elm would cause // potential patch errors down the road when it’s used as an insertion // reference node. Instead, we clone the node on-demand before creating // associated DOM element for it. vnode = ownerArray[index] = cloneVNode(vnode); } vnode.isRootInsert = !nested; // for transition enter check if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) { return } var data = vnode.data; var children = vnode.children; var tag = vnode.tag; // 有 tag 屬性,表示是元素節(jié)點(diǎn) if (isDef(tag)) { vnode.elm = vnode.ns ? nodeOps.createElementNS(vnode.ns, tag) // 創(chuàng)建元素。nodeOps 涉及到跨平臺(tái) : nodeOps.createElement(tag, vnode); setScope(vnode); /* istanbul ignore if */ { // 遞歸創(chuàng)建子節(jié)點(diǎn),并將子節(jié)點(diǎn)插入到父節(jié)點(diǎn)上 createChildren(vnode, children, insertedVnodeQueue); if (isDef(data)) {invokeCreateHooks(vnode, insertedVnodeQueue); } // 將 vnode 對應(yīng)的元素插入到父元素中 insert(parentElm, vnode.elm, refElm); } // isComment 屬性表示注釋節(jié)點(diǎn) } else if (isTrue(vnode.isComment)) { vnode.elm = nodeOps.createComment(vnode.text); // 插入父節(jié)點(diǎn) insert(parentElm, vnode.elm, refElm); // 否則就是子節(jié)點(diǎn) } else { vnode.elm = nodeOps.createTextNode(vnode.text); // 插入父節(jié)點(diǎn) insert(parentElm, vnode.elm, refElm); }}// 遞歸創(chuàng)建子節(jié)點(diǎn),并將子節(jié)點(diǎn)插入到父節(jié)點(diǎn)上。vnode 表示父節(jié)點(diǎn)function createChildren (vnode, children, insertedVnodeQueue) { if (Array.isArray(children)) { if (process.env.NODE_ENV !== ’production’) { checkDuplicateKeys(children); } // 依次創(chuàng)建子節(jié)點(diǎn),并將子節(jié)點(diǎn)插入到父節(jié)點(diǎn)中 for (var i = 0; i < children.length; ++i) { createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i); } } else if (isPrimitive(vnode.text)) { nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text))); }}刪除節(jié)點(diǎn) - 源碼分析

刪除節(jié)點(diǎn)非常簡單。直接看源碼:

// 刪除一組指定節(jié)點(diǎn)function removeVnodes (parentElm, vnodes, startIdx, endIdx) { for (; startIdx <= endIdx; ++startIdx) { var ch = vnodes[startIdx]; if (isDef(ch)) { if (isDef(ch.tag)) {removeAndInvokeRemoveHook(ch);invokeDestroyHook(ch); } else { // Text node// 刪除個(gè)節(jié)點(diǎn)removeNode(ch.elm); } } }}// 刪除單個(gè)節(jié)點(diǎn)function removeNode (el) { var parent = nodeOps.parentNode(el); // element may have already been removed due to v-html / v-text if (isDef(parent)) { // nodeOps里封裝了跨平臺(tái)的方法 nodeOps.removeChild(parent, el); }}

以上就是vue 虛擬DOM快速入門的詳細(xì)內(nèi)容,更多關(guān)于vue 虛擬DOM的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Vue
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
中文久久精品| 国产一区丝袜| 在线一区视频观看| 成人午夜在线| av资源亚洲| 激情五月色综合国产精品| 天堂中文av在线资源库 | 人人爱人人干婷婷丁香亚洲| 91亚洲成人| 蜜桃免费网站一区二区三区| av不卡在线| 日韩精品一级| 国产福利亚洲| 久久激情婷婷| 亚洲精品黄色| 久久超级碰碰| 激情久久婷婷| 日韩av中文字幕一区二区三区| 麻豆久久一区| 精品一区三区| 国产欧美日韩一级| 国产v综合v| 在线亚洲自拍| 精品久久不卡| 免费欧美在线视频| 激情久久99| 亚洲欧美日韩国产综合精品二区| 欧美亚洲tv| 国产精品88久久久久久| 国产亚洲一区| 99成人在线| 国产精品原创| 国产麻豆精品久久| 亚洲黄页一区| 日韩理论片av| 欧美精品影院| 久久国产福利| 日韩a一区二区| 亚洲免费毛片| 亚洲大片在线| 国际精品欧美精品| 97久久中文字幕| 久久亚洲图片| 欧美精品黄色| 成人日韩在线观看| 国产精品久久免费视频| 视频在线在亚洲| 欧美不卡视频| 欧美一级精品| 91精品一区国产高清在线gif| 精品免费视频| 国产伦理一区| 国产精一区二区| 深夜日韩欧美| 色婷婷成人网| 日韩精品欧美大片| 日本亚洲不卡| 日韩美女精品| 日韩成人精品一区二区| 九九九精品视频| 国精品产品一区| 久久99偷拍| 久久精品国产久精国产爱| 国产欧美另类| 国产精品久久久久久妇女| 日韩国产欧美视频| 中文字幕av一区二区三区四区| 国产韩日影视精品| 免费视频一区三区| 欧美特黄一区| 日韩精品免费一区二区夜夜嗨 | 国产欧美91| 国产高清亚洲| 成人精品高清在线视频| 黄色aa久久| 99国产一区| 99日韩精品| 蜜桃视频一区二区三区| 免费一级片91| 国产精品v亚洲精品v日韩精品| 久久精品99国产精品日本| 欧美成人精品一级| 亚洲免费福利| 亚洲一区国产一区| 国产日韩亚洲欧美精品| 特黄毛片在线观看| 亚洲精品美女91| 精品国产日韩欧美精品国产欧美日韩一区二区三区 | 97欧美在线视频| 欧美精选视频一区二区| 肉色欧美久久久久久久免费看| 精品一区在线| 国产丝袜一区| 午夜免费一区| 老司机精品视频网| 亚洲一级在线| av资源亚洲| 国产午夜久久av| 妖精视频成人观看www| 国产极品模特精品一二| 播放一区二区| 青青草国产精品亚洲专区无| 精品一区二区男人吃奶| 在线观看免费一区二区| 国产亚洲观看| 美女精品一区| 超级白嫩亚洲国产第一| 日本不卡视频在线| 91超碰国产精品| 国产一区二区三区天码| 日韩国产欧美在线播放| 日韩午夜一区| a天堂资源在线| 亚洲免费专区| 亚洲一区欧美二区| 视频在线不卡免费观看| 蜜臀精品一区二区三区在线观看 | 午夜国产欧美理论在线播放| 欧美激情aⅴ一区二区三区| 欧美高清一区| 红桃视频国产精品| av中文资源在线资源免费观看| 性色av一区二区怡红| 在线观看免费一区二区| 久久精品影视| 日韩不卡免费高清视频| 日韩激情一区| 久久视频一区| 999久久久免费精品国产| 国产在线|日韩| 欧美精品羞羞答答| 美女国产一区| 日本不卡高清| 国产精品久久久免费| 精品网站999| 色爱av综合网| 日本欧美不卡| 日韩国产欧美| 欧美日韩国产一区二区三区不卡| 最近高清中文在线字幕在线观看1| 成人在线黄色| 激情综合网五月| 日本一区免费网站| 久久99偷拍| 久久久蜜桃一区二区人| 每日更新成人在线视频| 欧美日韩伊人| 国产拍在线视频| japanese国产精品| 噜噜噜躁狠狠躁狠狠精品视频| 天堂av一区| 精品国产精品久久一区免费式| 国产aⅴ精品一区二区四区| 精品成av人一区二区三区| 久久九九精品| 日本不卡一二三区黄网| 97精品视频在线看| 亚洲制服欧美另类| 精品一区视频| 免费在线观看日韩欧美| 国产精品99久久精品| 免费视频一区二区| 亚洲综合电影| 日韩国产欧美三级| 成人午夜精品| 日韩福利视频网| 欧美中文一区二区| 婷婷精品在线| 欧美成人综合| 国产精品麻豆成人av电影艾秋 | 国产拍在线视频| 91九色综合| 免费美女久久99| 欧美精品一区二区久久| 精品伊人久久| 青青青国产精品| 国产一级一区二区| 91一区二区| 久久精品人人| 国产精品亚洲片在线播放| 免费在线观看一区二区三区| 午夜av不卡| 日韩在线观看一区| 精品国产91| 精品成av人一区二区三区| 国产亚洲欧美日韩在线观看一区二区 | 丝袜美腿成人在线| 国内激情久久| 欧美影院三区| 好吊日精品视频| 亚洲综合精品| 亚洲欧洲美洲国产香蕉| 人人精品人人爱| 日韩欧美久久| 国产精品一区二区精品视频观看 | 欧美伊人久久| 国产精品高清一区二区| 欧美国产极品| 日韩久久精品| 亚洲欧美日韩精品一区二区|