国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

用100行代碼畫出DOM樹狀結(jié)構(gòu)

Galence / 3274人閱讀

摘要:用行代碼畫出樹狀結(jié)構(gòu)這兩天寫了這樣一個(gè)小玩具,是一個(gè)可以把的樹狀結(jié)構(gòu)解析,并且畫出來的東西,把代碼寫到左邊,右邊就會(huì)自動(dòng)生成啦。繪圖部分依賴了百度開源的,核心功能的實(shí)現(xiàn)只有行代碼。如果是或者標(biāo)簽,那么進(jìn)入相應(yīng)的狀態(tài)

用100行代碼畫出DOM樹狀結(jié)構(gòu)

這兩天寫了這樣一個(gè)小玩具,是一個(gè)可以把DOM的樹狀結(jié)構(gòu)解析,并且畫出來的東西,把HTML代碼寫到左邊,右邊就會(huì)自動(dòng)生成啦。

點(diǎn)這里看DEMO

源碼在github · starkwang/DOM-Drawer,使用webpack打了個(gè)包。繪圖部分依賴了百度開源的 ECharts,核心功能的實(shí)現(xiàn)只有100行代碼。

核心代碼解讀

核心代碼分成兩部分,tokenizer 和 parser,流程的本質(zhì)上是一個(gè)最最最最簡(jiǎn)單的編譯器前端。

我們期望是把類似這樣的HTML字符串:

解析成這樣的對(duì)象:

{
    name : "div",
    children : [
        {
            name : "p",
            childern : []
        },
        {
            name : "img",
            childern : []
        },
        {
            name : "a",
            childern : []
        },
    ]
}
Tokenizer

tokenizer 負(fù)責(zé)把 HTML 字符串分割成一個(gè)由單詞、特殊符號(hào)組成的數(shù)組(去掉空格、換行符、縮進(jìn)),最后返回這個(gè)數(shù)組給 parser 進(jìn)行解析。

module.exports = tokenizer;
function tokenizer(content) {
    //結(jié)果數(shù)組
    var result = [];  
    
    //特殊符號(hào)的集合
    var symbol = ["{", "}", ":", ";", ",", "(", ")", ".", "#", "~", , "<", ">", "*", "+", "[", "]", "=", "|", "^"]; 
    
    //是否在字符串中,如果是的話,要保留換行、縮進(jìn)、空格 
    var isInString = false;
    
    //當(dāng)前的單詞棧
    var tmpString = "";
    
    
    for (var i = 0; i < content.length; i++) {
        //逐個(gè)讀取字符
        var t = content[i];
        
        //當(dāng)讀取到引號(hào)時(shí),進(jìn)入字符串狀態(tài)
        if (t == """ || t == """) {
            if (isInString) {
                tmpString += t;
                isInString = false;
                result.push(tmpString);
                tmpString = "";
            } else {
                tmpString += t;
                isInString = true;
            }
            continue;
        }
        
        
        if (isInString) {
            //字符串狀態(tài)
            tmpString += t;
        } else {
            //非字符串狀態(tài)
            
            if (t == "
" || t == " " || t == "    ") {
                //如果讀到了換行、空格或者tab,那么把當(dāng)前單詞棧中的字符作為一個(gè)單詞push到結(jié)果數(shù)組中,并清零單詞棧
                if (tmpString.length != 0) {
                    result.push(tmpString);
                    tmpString = "";
                }
                continue;
            }
            if (symbol.indexOf(t) != -1) {
                    //如果讀到了特殊符號(hào),那么把當(dāng)前單詞棧中的字符作為一個(gè)單詞push到結(jié)果數(shù)組中,清零單詞棧,再把這個(gè)特殊符號(hào)放進(jìn)結(jié)果數(shù)組
                if (tmpString.length != 0) {
                    result.push(tmpString);
                    tmpString = "";
                }
                result.push(t);
                continue;
            }
            //否則把字符推入單詞棧中
            tmpString += t;
        }
    }
    return result;
}
Parser

parser負(fù)責(zé)逐個(gè)讀取 tokenizer 生成的單詞序列,并且解析成一個(gè)樹形結(jié)構(gòu),這里用到了類似狀態(tài)機(jī)的思想。

module.exports = parser;
function parser(tokenArray) {

    //等下我們要從單詞序列中過濾出HTML標(biāo)簽
    var tagArray = [];
    
    //節(jié)點(diǎn)組成的棧,用于記錄狀態(tài)
    var nodeStack = [];
    
    //根節(jié)點(diǎn)
    var nodeTree = {
        name: "root",
        children: []
    };
    
    //是否在script、style標(biāo)簽內(nèi)部
    var isInScript = false,
        isInStyle = false;
    
    //先把根節(jié)點(diǎn)推入節(jié)點(diǎn)棧
    nodeStack.push(nodeTree);
    
    //一大堆單詞序列中過濾出HTML標(biāo)簽,注意這里沒有考慮到script、style中的特殊字符
    tokenArray.forEach(function(item, index) {
        if (item == "<") {
            tagArray.push(tokenArray[index + 1]);
        }
    })
    
    //HTML標(biāo)準(zhǔn)中自封閉的標(biāo)簽
    var selfEndTags = ["img", "br", "hr", "col", "area", "link", "meta", "frame", "input", "param"];
    
    
    tagArray.forEach(function(item, index) {
        //逐個(gè)讀取標(biāo)簽
        if (item[0] == "!" || selfEndTags.indexOf(item) != -1) {
            //自封閉標(biāo)簽、注釋、!DOCTYPE
            nodeStack[nodeStack.length - 1].children.push({
                name: item[0] == "!" && item[1] == "-" && item[2] == "-" ? "" : item,
                children: []
            });
        } else {
            //普通標(biāo)簽
            if (item[0] != "/") {
                //普通標(biāo)簽頭
                if (!isInScript && !isInStyle) {
                    //如果不在script或者style標(biāo)簽中,向節(jié)點(diǎn)棧尾部的children中加入這個(gè)節(jié)點(diǎn),并推入這個(gè)節(jié)點(diǎn),讓它成為節(jié)點(diǎn)棧的尾部
                    var newNode = {
                        name: item,
                        children: []
                    }
                    nodeStack[nodeStack.length - 1].children.push(newNode);
                    nodeStack.push(newNode);
                }
                
                //如果是script或者style標(biāo)簽,那么進(jìn)入相應(yīng)的狀態(tài)
                if (item == "script") {
                    isInScript = true;
                }
                if (item == "style") {
                    isInStyle = true;
                }
            } else {
                //普通標(biāo)簽尾
                if (item.split("/")[1] == nodeStack[nodeStack.length - 1].name) {
                    //如果這個(gè)標(biāo)簽和節(jié)點(diǎn)棧尾部的標(biāo)簽相同,那么認(rèn)為這個(gè)節(jié)點(diǎn)終止,節(jié)點(diǎn)棧推出。
                    nodeStack.pop();
                }
                
                //如果是script或者style標(biāo)簽,那么進(jìn)入相應(yīng)的狀態(tài)
                if (item.split("/")[1] == "script") {
                    isInScript = false;
                }
                if (item.split("/")[1] == "style") {
                    isInStyle = false;
                }
            }
        }
    })
    return nodeTree;
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/86131.html

相關(guān)文章

  • 前端每日實(shí)戰(zhàn):141# 視頻演示如何 CSS 的 Grid 布局創(chuàng)作一枚小狗郵票

    摘要:效果預(yù)覽按下右側(cè)的點(diǎn)擊預(yù)覽按鈕可以在當(dāng)前頁面預(yù)覽,點(diǎn)擊鏈接可以全屏預(yù)覽。可交互視頻此視頻是可以交互的,你可以隨時(shí)暫停視頻,編輯視頻中的代碼。 showImg(https://segmentfault.com/img/bVbhqjK?w=400&h=300); 效果預(yù)覽 按下右側(cè)的點(diǎn)擊預(yù)覽按鈕可以在當(dāng)前頁面預(yù)覽,點(diǎn)擊鏈接可以全屏預(yù)覽。 https://codepen.io/comehop...

    yintaolaowanzi 評(píng)論0 收藏0
  • 前端每日實(shí)戰(zhàn):141# 視頻演示如何 CSS 的 Grid 布局創(chuàng)作一枚小狗郵票

    摘要:效果預(yù)覽按下右側(cè)的點(diǎn)擊預(yù)覽按鈕可以在當(dāng)前頁面預(yù)覽,點(diǎn)擊鏈接可以全屏預(yù)覽。可交互視頻此視頻是可以交互的,你可以隨時(shí)暫停視頻,編輯視頻中的代碼。 showImg(https://segmentfault.com/img/bVbhqjK?w=400&h=300); 效果預(yù)覽 按下右側(cè)的點(diǎn)擊預(yù)覽按鈕可以在當(dāng)前頁面預(yù)覽,點(diǎn)擊鏈接可以全屏預(yù)覽。 https://codepen.io/comehop...

    Baoyuan 評(píng)論0 收藏0
  • JavaScript 編程精解 中文第三版 十七、在畫布上繪圖

    摘要:貝塞爾曲線方法可以繪制一種類似的曲線。不同的是貝塞爾曲線需要兩個(gè)控制點(diǎn)而不是一個(gè),線段的每一個(gè)端點(diǎn)都需要一個(gè)控制點(diǎn)。下面是描述貝塞爾曲線的簡(jiǎn)單示例。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項(xiàng)目原文:Drawing on Canvas 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 自豪地采用谷歌翻譯 部分參考了《JavaScript 編程精解(第 2...

    habren 評(píng)論0 收藏0
  • DOM操作筆記

    摘要:它實(shí)際上等于清除當(dāng)前文檔流,重新寫入內(nèi)容方法用于關(guān)閉方法所新建的文檔。如果頁面已經(jīng)渲染完成關(guān)閉了,再調(diào)用方法,它會(huì)先調(diào)用方法,擦除當(dāng)前文檔所有內(nèi)容,然后再寫入我們的頁面渲染的時(shí)候就會(huì)去打開一個(gè)文檔流,當(dāng)渲染繪制結(jié)束,就關(guān)閉這個(gè)文檔流。 一、DOM簡(jiǎn)介 1、定義: DOM 是 JavaScript 操作網(wǎng)頁的接口,全稱為文檔對(duì)象模型(Document Object Model)。 2、作...

    newtrek 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<