您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關怎么在react中實現一個虛擬dom和diff算法,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
虛擬DOM,見名知意,就是假的DOM,我們真實的DOM掛載在頁面上的,而我們的虛擬DOM則是在內存中的。這個就需要我們把真實的DOM抽象成一個對象放在內存中。這個對象就可以是如下類型:
var element = { tagName: 'div', props: { class: 'box' }, children: { { tagName: 'p', props: { class: 'p1' }, children: ['我是p1'] }, { tagName: 'p', props: { class: 'p2' }, children: ['我是p2'] }, { tagName: 'p', props: { class: 'p3' }, children: ['我是p3'] }, } }
我們想要構造出這樣的對象可以自己封裝一個構造函數如下:
function Element(tagName, props, children) { this.tagName = tagName this.props = props this.children = children }
有了這個對象,我們需要把這個虛擬DOM渲染到真實DOM上,可以寫出如下方法:
Element.prototype.render = function () { const { tagName, props, children } = this var el = document.createElement(tagName) for (key in props) { el.setAttribute(key, props[key]) } children.forEach((item) => { const childEl = (item instanceof Element) ? item.render() : document.createTextNode(item) el.appendChild(childEl) }) return el }
最后我們可以new出這個對象調用render()方法然后appendChild到body中就好了:
let virtualDom = new Element('div', { class: 'box' }, [ new Element('p', { class: 'p1' }, ['我是p1']), new Element('p', { class: 'p2' }, ['我是p2']), new Element('p', { class: 'p3' }, ['我是p3']), ]) let a = virtualDom.render() document.body.appendChild(a)
首先我們先了解一下diff算法的作用
如果我們的虛擬dom發生了變化,我們的內存中又會產生新的虛擬DOM,如果我們直接用這個新的虛擬DOM結構的話,又會導致很多重復的渲染,因此 這個時候diff算法的作用就體現了出來,diff通過比較新舊兩個虛擬DOM樹,找出差異,并且記錄下來,然后把記錄的差異應用到真實的DOM樹上。
原理:
diff算法通過對新舊兩顆樹進行深度優先遍歷,每一個節點都加一個唯一的標識。
這個過程分為2步
找出兩個樹的差異,并記錄在一個偽數組里。
把這些不同應用到真實的DOM樹上
對于dom的操作基本可化為4種類型
對節點的刪除,移動,添加子節點
更換節點標簽
對于文本節點,修改節點文本
修改節點props
下面會用偽代碼的形式大致過一下這個流程
// diff 函數,對比兩棵樹 function diff(oldTree, newTree) { var patchs = {}; // 偽數組,記錄差異 // 對4種節點做錯判斷 dfWork(oldTree, newTree, patchs, index) return patchs } function dfWork(oldTree, newTree, patchs, index) { let currentPatch = [] if (1) { // 對節點的刪除 currentPatch.push() } else if (3) { // 對節點的文本的更換 currentPatch.push() } else { // 修改節點的props 對children的檢查 // 對props作diff算法,把變化記錄到patchs中。 currentPatch.push({ type: patch.PROPS, props: propsPatches }) // 然后需要對子節點作diff算法 diffChildren(oldNode.children, newNode.children, index, patches, currentPatch) } } function diffChildren(oldChildren, newChildren, index, patches, currentPatch) { // 對子節點作diff算法,遍歷子節點,遞歸調用dfWork,做差異得到patchs } // 把變化應用在真實的DOM樹上 function patch(node, patchs) { // node為老的DOM樹,patchs變化。 // 我們會遍歷這個patchs,并且把node和patch對應上, } function applyPatch(node, patchs) { // 應為每個節點可能有多個變化,所以也需要遍歷 switch (patchs.type) { case REPLACE: // 節點替換 // node.render() break; case REORDER: // 節點的移動刪除新增子節點。 break; case PROPS: // setProps break; case TEXT: // 對節點文本的修改 // node.nodeValue break; default: break; } }
關于怎么在react中實現一個虛擬dom和diff算法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。