手動實現HTML外掛Beautify
學習HTML-Beautify.js之後,我們發現使用JavaScript對HTML進行解析也並不神秘, 首先是逐字元進行分析,從中提取標記(Token),在HTML只存在兩種型別的標記-標籤和正文, 然後對這些Token進行語法分析,主要是縮排量是多少。
在有這些基本概念後,今天我們就自己來實現這個小程式:
// 最佳化過的HTML-Beautify function HtmlBeautify(source, indent_value) { this.source = source; this.indent_value = indent_value; this.result = ""; this.parse(); } // 分析併產生輸出到this.result HtmlBeautify.prototype.parse = function() { var that = this; // 當前分析到哪個字元,當前標記值,標記型別, // 輸出陣列,縮排級別,當前格式化內容(去掉多餘空格) var pos = 0, token_value = "", token_type = "", output = [], indent_level = 0, is_format_content = true; // 把這些標籤作為Single Tag var single_token = "br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed".split(','); var white_space = "rnt ".split(""); // 獲取下一個標記(首先獲取正文,如果正文為空則獲取標籤) function nextToken() { var token_value_array = [], val = "", space = false; // "<"之前的所有內容作為正文標籤 while ((val = that.source[pos]) !== "<") { if (pos >= that.source.length) { token_type = "END"; return; } if (is_format_content) { if ($.inArray(val, white_space) >= 0) { space = true; pos++; continue; } if (space) { token_value_array.push(" "); space = false; } } token_value_array.push(val); pos++; } token_value = token_value_array.join("").replace(/^n+|n$/g,""); if ($.trim(token_value) === "") { // 如果正文標記為空,則獲取標籤標記 if(!is_format_content) { is_format_content = true; } nextTokenTag(); } else { token_type = "CONTENT"; } } // 下一個標籤標記 function nextTokenTag() { var token_value_array = [], val = "", tagName = "", space = false, is_comment = false; // 這是一個註釋標籤 if(that.source[pos + 1] === "!" && that.source[pos + 2] === "-" && that.source[pos + 3] === "-") { is_comment = true; } // 獲取標籤標記,直到遇到">" do { val = that.source[pos]; if (!is_comment) { // 如果此字元為空格換行製表符,則跳過此字元 if ($.inArray(val, white_space) >= 0) { space = true; pos++; continue; } if (space) { if(token_value_array[token_value_array.length - 1] !== "=" && val !== "=") { token_value_array.push(" "); } space = false; } } if(val === "/" && that.source[pos + 1] === ">" && token_value_array[token_value_array.length - 1] !== " ") { token_value_array.push(" "); } token_value_array.push(val); pos++; } while (val !== ">"); token_value = $.trim(token_value_array.join("")); // 當前標籤的名稱(小寫) tagName = getTagName(); if(is_comment) { token_type = "SINGLE_TAG"; } else { if (token_value[1] === "/") { // token_value以"</"開始,則認為是結束標籤 token_type = "END_TAG"; } else if ($.inArray(tagName, single_token) >= 0 || token_value[token_value.length - 2] === "/") { // 如果標籤在single_token或者token_value以"/>"結尾,則認為是獨立標籤 // 這種判斷沒有考慮這種情況:"<br></br>" token_type = "SINGLE_TAG"; } else { token_type = "START_TAG"; if (tagName === "script" || tagName === "style") { is_format_content = false; } } } } function getTagName() { var tagName = token_value.substr(1, token_value.length - 2); var spaceIndex = tagName.indexOf(" "); if (spaceIndex > 0) { tagName = tagName.substr(0, spaceIndex); } return tagName.toLowerCase(); } // 輸出當前標記 function outputToken() { output.push(token_value); } // 輸出新行 function outputLine() { output.push("n"); } // 輸出縮排 function outputIndent() { for (var i = 0; i < indent_level; i++) { output.push(that.indent_value); } } // parse的主體函式,迴圈獲取下一個Token while (true) { nextToken(); // 當前Token為結束標記 if (token_type === "END") { break; } switch (token_type) { case "START_TAG": // 我們對縮排的控制非常簡單,開始標籤後縮排一個單位 outputLine(); outputIndent(); outputToken(); indent_level++; break; case "END_TAG": // 結束標籤前減少一個單位縮排 indent_level--; outputLine(); outputIndent(); outputToken(); break; case "SINGLE_TAG": outputLine(); outputIndent(); outputToken(); break; case "CONTENT": outputLine(); if(is_format_content) { outputIndent(); } outputToken(); break; } } // 去除最前面的"n" this.result = output.join("").substr(1); }; $(function() { $("#format").click(function() { // 例項化HtmlBeautify,傳遞需要解析的HTML片段和縮排字串 var beautify = new HtmlBeautify($("#content").val(), " "); $("#content").val(beautify.result); }); });
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2331/viewspace-2800840/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 自己實現HTML-BeautifyHTML
- VSCode外掛之BeautifyVSCode
- Beautify Panel for Mac(PS人像磨皮美容外掛)Mac
- jQuery實現的元素抖動外掛jQuery
- eclipse 手動/自動安裝外掛Eclipse
- 自己動手編寫一個Mybatis外掛:Mybatis脫敏外掛MyBatis
- PHP外掛系統的實現(四):實現註冊動作PHP
- 來一手Flutter Web =-= 實現高德地圖外掛FlutterWeb地圖
- PHP外掛系統的實現(七):外掛案例PHP
- 自己動手搞一個tip 外掛
- react實現移動端PDF線上預覽外掛React
- PHP外掛系統的實現(五):觸發外掛PHP
- 谷歌外掛 HTML-to-Markdown谷歌HTML
- QQ搶紅包外掛實現
- xlam外掛製作實驗手冊
- Android外掛化技術之旅 1 開篇 - 實現啟動外掛與呼叫外掛中的Activity和ServiceAndroid
- YII框架 外掛引入問題,手動引入 redis外掛, class "yii\redis\Cache".框架Redis
- intellijIDEA手動安裝Scala外掛IntelliJIdea
- 讓人心動的jQuery外掛和HTML5動畫jQueryHTML動畫
- jquery實現的垂直或者水平無縫滾動外掛jQuery
- JavaScript原生實現樓梯外掛JavaScript
- javascript實現的微信分享外掛JavaScript
- jQuery實現的cookie操作外掛jQueryCookie
- PHP外掛系統的實現(二):獲取全部外掛資訊PHP
- 外掛化知識梳理(10) Service 外掛化實現及原理
- 【AST篇】教你如何動手寫 Eslint 外掛ASTEsLint
- 自己動手擴充套件vim外掛——配色篇套件
- Spring Boot 如何熱載入 jar 實現動態外掛?Spring BootJAR
- Spring Boot 如何熱載入jar實現動態外掛?Spring BootJAR
- 手牽手教你寫 Vue 外掛Vue
- 外掛化知識梳理(4) Small 框架之如何實現外掛更新框架
- 【Maven實戰技巧】「外掛使用專題」Maven-Assembly外掛實現自定義打包Maven
- 從零實現一個 VuePress 外掛Vue
- AppDomain實現【外掛式】開發APPAI
- 騰訊地圖SDK Flutter外掛實現地圖Flutter
- PHP外掛系統的實現(一)PHP
- 使用spring外掛實現策略模式Spring模式
- 【MyBatis原始碼分析】外掛實現原理MyBatis原始碼