偉大的虛擬DOM到真實(shí)DOM的過程

最近在看一些源碼學(xué)習(xí)文章,今晚上等發(fā)版有空就記錄一下吧。

1、什么是虛擬DOM

已經(jīng)9102年了,前端er或多或少都接觸過一些mvvm庫(kù),了解有虛擬DOM這么個(gè)東西,可能你還沒有深入了解過這個(gè)東西,其實(shí)很簡(jiǎn)單,來(lái)往下看。

虛擬DOM簡(jiǎn)而言之就是,用JS去按照DOM結(jié)構(gòu)來(lái)實(shí)現(xiàn)的樹形結(jié)構(gòu)對(duì)象也就是一個(gè)JS對(duì)象而已。

2、什么樣的對(duì)象才能比較匹配的上dom結(jié)構(gòu)呢

來(lái)看一下如下圖所示的dom結(jié)構(gòu)

image.png

上圖是比較簡(jiǎn)單的一個(gè)結(jié)構(gòu),比較理想的是使用如下對(duì)象來(lái)模擬:

{
    // 節(jié)點(diǎn)類型
    type: 'ul',
    // 節(jié)點(diǎn)的屬性,包括dom原生屬性和自定義屬性
    props: {
        class: 'list',
        style: 'color:red;'
    },
    // 子節(jié)點(diǎn)數(shù)組
    // 子對(duì)象結(jié)構(gòu)也是一樣,包含了type,props,children,沒有子節(jié)點(diǎn)的話就是普通文本
    // 子對(duì)象擁有子節(jié)點(diǎn)時(shí),繼續(xù)往下擴(kuò)展就行
    children: [
        {type: 'li',props: {class: 'list'},children: ['利群']},
        {type: 'li',props: {class: 'list'},children: ['玉溪']},
        {type: 'li',props: {class: 'list'},children: ['黃鶴樓']}
    ]
}

OK,對(duì)象結(jié)構(gòu)已經(jīng)解析完成

3、批量創(chuàng)建這個(gè)對(duì)象---終于可以上代碼了
// 定義一個(gè)構(gòu)造函數(shù)來(lái)
class Element {
    constructor(type, props, children) {
        this.type = type;
        this.props = props;
        this.children = children;
    }
}

//批量調(diào)用構(gòu)造函數(shù)
function createElement(type,props,children){
    return new Element(type,props,children);
}

let virtualDom = createElement('ul',{class:'list',style:'color:red;'},[
        createElement('li',{class:'item'},['利群']),
        createElement('li',{class:'item'},['玉溪']),
        createElement('li',{class:'item'},['黃鶴樓']),
    ]);

// 對(duì)象形勢(shì)的結(jié)構(gòu)展示
console.log(virtualDom);

OK,查看打印出來(lái)的對(duì)象是這樣的


image.png
4、將虛擬的DOM對(duì)象渲染成真實(shí)的DOM,添加兩個(gè)方法
// 把虛擬對(duì)象轉(zhuǎn)成dom對(duì)象
function render(domObj) {
    // 根據(jù)元素類型來(lái)創(chuàng)建dom
    let el = document.createElement(domObj.type);

    // 遍歷props對(duì)象,然后給創(chuàng)建的元素el設(shè)置屬性
    for (let key in domObj.props) {
        // 設(shè)置屬性的方法
        setAttr(el, key, domObj.props[key]);
    }

    // 遍歷子節(jié)點(diǎn)數(shù)組
    domObj.children.forEach(child = >{
        // 需要注意的是:如果child是虛擬dom,就繼續(xù)遞歸渲染
        if (child instanceof Element) {
            child = render(child);
        } else {
            // 只是普通的文本內(nèi)容
            child = document.createTextNode(child);
        }
        // 把子節(jié)點(diǎn)添加到父節(jié)點(diǎn)中
        el.appendChild(child);
    });

    return el;
}

// 上面用到的設(shè)置屬性
function setAttr(node, key, value) {
    // 需要判斷key是什么
    switch (key) {
    case 'value':
        // 屬性是value就要看標(biāo)簽類型了,input和textarea的value就需要做區(qū)別
        if (node.tagName.toLowerCase() === 'input' || node.tagName.toLowerCase() == 'textarea') {
            node.value = value;
        } else {
            node.setAttribute(key, value);
        }
        break;
    case 'style':
        node.style.cssText = value;
        break;
    default:
        node.setAttribute(key, value);
        break;
    }
}

// 將元素插入頁(yè)面
function renderDom(el, target) {
    target.appendChild(el);
}

// 定義一個(gè)構(gòu)造函數(shù)來(lái)
class Element {
    constructor(type, props, children) {
        this.type = type;
        this.props = props;
        this.children = children;
    }
}

//批量調(diào)用構(gòu)造函數(shù)
function createElement(type,props,children){
    return new Element(type,props,children);
}

// 調(diào)用之前的createElement方法
let virtualDom = createElement('ul',{class:'list',style:'color:red;'},[
        createElement('li',{class:'item'},['利群']),
        createElement('li',{class:'item'},['玉溪']),
        createElement('li',{class:'item'},['黃鶴樓']),
    ]);

// 對(duì)象形勢(shì)的結(jié)構(gòu)展示
console.log(virtualDom);
            
// 渲染dom
let el = render(virtualDom); // 得到dom元素
console.log(el);
renderDom(el,document.querySelector('body'));

OK,結(jié)果如下:

image.png

寫的并不是很清晰,需要一行一行看下來(lái)啦...eemme,有待提升,我改bug去了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,665評(píng)論 1 32
  • 文章結(jié)構(gòu): React中的虛擬DOM是什么? 虛擬DOM的簡(jiǎn)單實(shí)現(xiàn)(diff算法) 虛擬DOM的內(nèi)部工作原理 Re...
    李輕舟閱讀 3,207評(píng)論 2 14
  • 海風(fēng)輕撫 夾雜著淡淡的腥味 翻滾的浪花 大海在傾訴 鷹擊長(zhǎng)空 隨主沉浮 海鷗在天空中翱翔 與風(fēng)浪為伴 戀人依偎在一...
    家鄉(xiāng)雪韻閱讀 518評(píng)論 5 13
  • 耳畔響起的一曲音樂,把我?guī)У搅颂瞥?,帶到了牡丹花冷笑天下的時(shí)代。黃昏下,詩(shī)人自小院里走出,一身灰白的質(zhì)樸錯(cuò)落在籬笆...
    廣電1702b23余蕊閱讀 300評(píng)論 0 0
  • 。
    Fliz閱讀 230評(píng)論 0 1

友情鏈接更多精彩內(nèi)容