成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用100行代碼畫出DOM樹狀結構

Galence / 3279人閱讀

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

用100行代碼畫出DOM樹狀結構

這兩天寫了這樣一個小玩具,是一個可以把DOM的樹狀結構解析,并且畫出來的東西,把HTML代碼寫到左邊,右邊就會自動生成啦。

點這里看DEMO

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

核心代碼解讀

核心代碼分成兩部分,tokenizer 和 parser,流程的本質上是一個最最最最簡單的編譯器前端。

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

解析成這樣的對象:

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

tokenizer 負責把 HTML 字符串分割成一個由單詞、特殊符號組成的數組(去掉空格、換行符、縮進),最后返回這個數組給 parser 進行解析。

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

parser負責逐個讀取 tokenizer 生成的單詞序列,并且解析成一個樹形結構,這里用到了類似狀態(tài)機的思想。

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

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

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

轉載請注明本文地址:http://systransis.cn/yun/86131.html

相關文章

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

    摘要:效果預覽按下右側的點擊預覽按鈕可以在當前頁面預覽,點擊鏈接可以全屏預覽??山换ヒ曨l此視頻是可以交互的,你可以隨時暫停視頻,編輯視頻中的代碼。 showImg(https://segmentfault.com/img/bVbhqjK?w=400&h=300); 效果預覽 按下右側的點擊預覽按鈕可以在當前頁面預覽,點擊鏈接可以全屏預覽。 https://codepen.io/comehop...

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

    摘要:效果預覽按下右側的點擊預覽按鈕可以在當前頁面預覽,點擊鏈接可以全屏預覽??山换ヒ曨l此視頻是可以交互的,你可以隨時暫停視頻,編輯視頻中的代碼。 showImg(https://segmentfault.com/img/bVbhqjK?w=400&h=300); 效果預覽 按下右側的點擊預覽按鈕可以在當前頁面預覽,點擊鏈接可以全屏預覽。 https://codepen.io/comehop...

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

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

    habren 評論0 收藏0
  • DOM操作筆記

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

    newtrek 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<