摘要:用行代碼畫出樹狀結構這兩天寫了這樣一個小玩具,是一個可以把的樹狀結構解析,并且畫出來的東西,把代碼寫到左邊,右邊就會自動生成啦。繪圖部分依賴了百度開源的,核心功能的實現只有行代碼。如果是或者標簽,那么進入相應的狀態(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
摘要:效果預覽按下右側的點擊預覽按鈕可以在當前頁面預覽,點擊鏈接可以全屏預覽??山换ヒ曨l此視頻是可以交互的,你可以隨時暫停視頻,編輯視頻中的代碼。 showImg(https://segmentfault.com/img/bVbhqjK?w=400&h=300); 效果預覽 按下右側的點擊預覽按鈕可以在當前頁面預覽,點擊鏈接可以全屏預覽。 https://codepen.io/comehop...
摘要:效果預覽按下右側的點擊預覽按鈕可以在當前頁面預覽,點擊鏈接可以全屏預覽??山换ヒ曨l此視頻是可以交互的,你可以隨時暫停視頻,編輯視頻中的代碼。 showImg(https://segmentfault.com/img/bVbhqjK?w=400&h=300); 效果預覽 按下右側的點擊預覽按鈕可以在當前頁面預覽,點擊鏈接可以全屏預覽。 https://codepen.io/comehop...
摘要:貝塞爾曲線方法可以繪制一種類似的曲線。不同的是貝塞爾曲線需要兩個控制點而不是一個,線段的每一個端點都需要一個控制點。下面是描述貝塞爾曲線的簡單示例。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項目原文:Drawing on Canvas 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 自豪地采用谷歌翻譯 部分參考了《JavaScript 編程精解(第 2...
閱讀 2431·2021-11-16 11:44
閱讀 857·2021-09-10 11:16
閱讀 2234·2019-08-30 15:54
閱讀 1065·2019-08-30 15:53
閱讀 1913·2019-08-30 13:00
閱讀 625·2019-08-29 17:07
閱讀 3519·2019-08-29 16:39
閱讀 3141·2019-08-29 13:30