第294天:簡單模板模式

2021-02-21 山科小站
簡單模板模式

簡單模板模式是通過格式化字符串拼接出視圖避免創建視圖時大量的節點操作,簡單模板模式不屬於通常定義的設計模式範疇。

描述

對比於模板方法模式,其定義了如何執行某些算法的框架,通過父類公開的接口或方法子類去實現或者是調用,而簡單模板模式是用來解決為了創建視圖的大量節點操作,並在此基礎上解決數據與結構的強耦合性。

節點操作

如果我們要生成一個列表,直接通過各類節點操作是相對比較麻煩的。

<!DOCTYPE html>
<html>
<head>
<title>節點操作</title>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/javascript">
(function(){
const container = document.getElementById("root");
const ul = document.createElement("ul");
const list = [{
"name": "google",
"url": "https://www.google.com"
}, {
"name": "baidu",
"url": "https://www.baidu.com"
}, {
"name": "bing",
"url": "https://cn.bing.com"
}];
list.forEach(v => {
let li = document.createElement("li");
let a = document.createElement("a");
a.href = v.url;
a.target = "_blank";
a.innerText = v.name;
li.appendChild(a);
ul.appendChild(li);
});
container.appendChild(ul);
})();
</script>
</html>

基於字符串拼接

如果我們使用字符串拼接,雖然能夠減少看上去的複雜程度,但是實際由於數據和結構強耦合導致可維護性通常比較差,這導致的問題是如果數據或者結構發生變化時,都需要改變代碼。此外此處使用了ES6的模板字符串語法動態生成了一個ul列表,看上去貌似不會複雜,如果直接使用字符串拼接,會繁瑣很多。

<!DOCTYPE html>
<html>
<head>
<title>字符串拼接</title>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/javascript">
(function(){
const container = document.getElementById("root");
const list = [{
"name": "google",
"url": "https://www.google.com"
}, {
"name": "baidu",
"url": "https://www.baidu.com"
}, {
"name": "bing",
"url": "https://cn.bing.com"
}];
let template = `<ul>`;
list.forEach(v => {
template += `<li>
<a href="${v.url}" target="_blank" >${v.name}</a>
</li>`;
});
template += "</ul>";
container.innerHTML = template.replace(/[\s]+/g, " ");
})();
</script>
</html>

模板渲染

通過創建模板,我們可以使用數據去格式化字符串來渲染視圖並插入到容器中,這樣實現的方案可讀性會高很多。

<!DOCTYPE html>
<html>
<head>
<title>模板渲染</title>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/javascript">
(function(){
const container = document.getElementById("root");
const formatString = function(str, data){
return str.replace(/\{\{(\w+)\}\}/g,
(match, key) => typeof(data[key]) === void 0 ? "" : data[key]);
}
const list = [{
"name": "google",
"url": "https://www.google.com"
}, {
"name": "baidu",
"url": "https://www.baidu.com"
}, {
"name": "bing",
"url": "https://cn.bing.com"
}];
let template = ["<ul>"];
list.forEach(v => {
template.push("<li>");
template.push(formatString('<a href="{{url}}" target="_blank" >{{name}}</a>', v));
template.push("</li>");
});
template.push("</ul>");
console.log(template)
container.innerHTML = template.join("");
})();
</script>
</html>

模板引擎的簡單實現

對mustcache風格的{{}}進行簡單的實現,僅對於其數據的展示方面有實現,對於其指令例如循環等並未實現,通過處理字符串,將其轉換為一個函數並傳參執行,即可實現數據的展示。通過對於字符串的處理並使用Function實現模板語法,如果使用正則表達式進行較為完整的過濾,是完全可以生成較為完善的模板語法的處理的,包括Js的表達式以及自帶指令等,如mustcache.js、layui.js的laytpl模塊。

<!DOCTYPE html>
<html>
<head>
<title>模板引擎</title>
</head>
<body>
<div id="root">
<div>{{show}}</div>
<div>{{description}}</div>
</div>
</body>
<script type="text/javascript">
var data = {
show: 1,
description: "一個簡單的模板引擎"
};

function render(element, data) {
var originString = element.innerHTML;
var html = String(originString||'').replace(/"/g,'\\"').replace(/\s+|\r|\t|\n/g, ' ')
.replace(/\{\{(.)*?\}\}/g, function(value){
return value.replace("{{",'"+(').replace("}}",')+"');
})
html = `var targetHTML = "${html}";return targetHTML;`;
var parsedHTML = new Function(...Object.keys(data), html)(...Object.values(data));
element.innerHTML = parsedHTML;
}

render(document.getElementById("root"), data);
</script>
</html>

AST

基於AST的模板語法需要解析HTML成為AST,然後將AST轉化為字符串,將字符串作為函數執行,這個過程依舊需要用到Function,下邊的例子只是藉助了Js取得DOM結構生成的AST,沒有自行解析HTML。雖然看起來最後都需要使用Function去處理字符串,而AST還需要解析HTML然後再拼接字符串,增加了計算的時間,但是如果僅僅是完全基於處理字符串的方式實現的模板語法,在數據進行變更時都需要進行render,每次render的時候都需要重新渲染整個DOM,雖然在上邊的簡單實現中AST也是重新渲染了整個模版,但是現在主流的Js框架例如Vue就是基於AST的方式,首先解析template為AST,然後對於AST進行靜態節點標記,用以標記靜態的節點進行重用跳過比對,從而進行渲染優化,然後生成虛擬DOM,當數據進行變更時虛擬DOM會進行diff算法的比對,找到數據有變更的節點,然後進行最小化渲染,這樣就不需要在數據變更時將整個模板進行渲染,從而增加了渲染的效率。

<!DOCTYPE html>
<html>
<head>
<title>AST</title>
</head>
<body>
<div id="root" class="root-node">
<div>{{show}}</div>
<div>{{description}}</div>
</div>
</body>
<script type="text/javascript">
var data = {
show: 1,
description: "一個簡單的模板語法"
};

function parseAST(root){
var node = {};
node.parent = null;
if(root.nodeName === "#text"){
node.type = "text";
node.tagName = "text";
node.content = root.textContent.replace(/\s+|\r|\t|\n/g, ' ').replace(/"/g,'\\"');
}else{
node.type = "tag";
node.tagName = root.localName;
node.children = [];
node.attr = {};
Array.prototype.forEach.call(root.attributes, item => node.attr[item.nodeName] = item.nodeValue );
}
Array.prototype.forEach.call(root.childNodes, element => {
var parsedNode = parseAST(element);
parsedNode.parent = root;
node.children.push(parsedNode);
});
return node;
}

function render(element, template, data) {
html = `var targetHTML = "${template}";return targetHTML;`;
var parsedHTML = new Function(...Object.keys(data), html)(...Object.values(data));
element.innerHTML = parsedHTML;
}

function generateHTMLTemplate(AST){
var template = "";
AST.forEach( node => {
if(node.type === "tag"){
template += `<${node.tagName}>`;
template += generateHTMLTemplate(node.children);
template += `</${node.tagName}>`;
}else{
if(node.content.match(/\{\{(.)*?\}\}/)){
var expression = node.content.replace(/\{\{(.)*?\}\}/g, function(value){
return value.replace("{{",'"+(').replace("}}",')+"');
})
template += expression;
}else{
template += node.content;
}
}
})
return template;
}

var root = document.getElementById("root");
var AST = parseAST(root);
var template = generateHTMLTemplate([AST]);
render(root, template, data);
</script>
</html>

每日一題
https://github.com/WindrunnerMax/EveryDay

參考
https://juejin.cn/post/6844903633000087560
https://www.cnblogs.com/libin-1/p/6544519.html
https://github.com/sentsin/layui/blob/master/src/lay/modules/laytpl.js

相關焦點

  • 【文明實踐在行動】第294期 滿月酒取消了,婚期延遲了
    【文明實踐在行動】第294期 滿月酒取消了,婚期延遲了 2021-01-18 10:00 來源:澎湃新聞·澎湃號·政務
  • 國慶節手抄報,文字、邊框、模板都有了!簡單又漂亮!
    今天,我為大家整理了一些素材,文字、邊框、模板等。有需要的家長,先收藏起來吧!1文字素材文字內容,是手抄報的靈魂。國慶節手抄報,內容可以選擇跟國旗、國徽、國歌相關的內容。歌頌祖國的優美詩句,社會主義核心價值觀等等。我為大家精選了一些內容,可以作參考。
  • 跨越294個日夜的感謝!
    11月6日,北京市公安局監所管理總隊民警王俊傑收到市民劉女士送來的致謝錦旗,一頭霧水的他這才想起294天前發生的那一幕。11月6日,劉女士代表家人將一面印有「見義勇為 熱心助民」的錦旗送到看守所,將這一份跨越294個日夜的感恩送到了王俊傑手中,以表達對王俊傑在孩子生命垂危時刻提供無私幫助的感謝。王俊傑今年53歲,從事公安監管工作已經33年了。當同事知道他幫助群眾的事跡時,並不感到驚訝,因為在大家眼裡,他就是一個「熱心腸」,有求必應。
  • Excel實用工具11:任務矩陣模板
    本來想著自已有時間再開發一套這樣的模板的,想不到在trumpexcel.com中已經有了。
  • Excel實用工具7:Excel日曆模板
    本文介紹的這兩款Excel模板,由trumpexcel.com開發,使用Excel公式創建動態的日曆模板
  • 伊波拉恐怖之謎:以人類基因做模板進行複製,第四級病毒無法治癒
    由於這樣慘烈的高致死率,世界衛生組織把伊波拉,列為對人類危害最嚴重的病毒之一——第四級病毒。第四級病毒是指在實驗室裡進行分離、實驗微生物組織結構時安全隔離分級的最高等級,它們給人類造成致命的疾病,並且在絕大多數情況下是不可救治的,死亡率最高。除了伊波拉,馬爾堡病毒和拉沙病毒等也屬於第四級病毒。
  • WIX.com:Freemium的生意模式
    WIX.com的使用非常簡單,用戶只需要通過拖拉方式即可將圖片、連結、視頻等放在wix提供的網站模板,完成網站的建設。現在的wix.com已經成為用戶進行客戶關係管理、市場營銷、工作流程管理、支付、媒體管理等等的一站式的作業系統(WIXOS)。WIX.com允許用戶免費使用,但是,如果用戶想使用更加複雜的功能,就需要支付年費或者月費,這便是WIX的Freemium的商業模式。
  • 父親節 | 這9款免費立體卡模板,最適合送父親
    其中有簡單的DIY愛心立體書,也有複雜些的茶杯花束卡片,更有「小象」、「小熊」、「美酒」這些非常貼合父親主題的卡片。模板庫已經重新排序,方便大家查找。不如這兩天就做一張,作為父親節最好的禮物,送給親愛的父親吧!製作難度:簡單來自馬休·萊因哈特官網。簡單V形折平行折組合而成,可填色DIY製作。
  • 中文作文模板
    又到了周五了,小編給大家準備了比較實惠的中文大作文寫作模板,根據高分學長學姐的講解,以及小編的匯總,簡單的模板慕白雙手奉上!!!
  • 創新創效 | 用模板拼「拼圖」
    「用了新型模板體系,這暗埋段CW01澆注比當初預計的工期快了至少有一個星期吧?」「快了整整10天。」面對監理的詢問,公司深中通道項目部的技術員們露出了難得的笑容。暗埋段隧道CW01混凝土澆注是島隧結合部施工的重要一環,由於澆注體量巨大,設計單位又將其分為CW1-1、CW1-2、CW1-3、CW1-4等4段隧道進行施工。
  • 託福口語:考試能不能用模板
    一.託福口語備考要不要用模板  1. 用不用託福口語模板,看你對分數的要求。
  • 高濃度乾貨:考研英語寫作模板到底怎麼搭?(一)
    買填6個詞的模板是騙自己,更是把閱卷老師當傻子!我們提供的模板也是給你足夠替換空間的,並且想要作文拿高分,模板更需要DIY,那麼模板怎麼建? 英1:大作文第一段:1)引入句(不要長,要簡明,不要廢話套話)新穎一點可以考慮:看到這幅圖我想到的第一句話是…./ 這幅圖引起我…(悲傷/憤怒等)的感覺2)第一個主體的描述公式(常見的有地點倒裝或分詞倒裝的句型)3)補充描述的公式
  • 「我不知道她叫什麼名字,但是她總在這裡守著…」22天風雨無阻,她成了老舊小區的「門神」!
    從3月2日開始,一把額溫槍、一本登記表、一把紫色的小椅子,便是李芳芳身為虹山東路294號"門神"的全部裝備。虹山東路294號是老舊小區,沒有物管,外來租戶比較多。虹山東路社區志願者 李芳芳:「麻煩量下體溫,你們是來看房還是什麼?我給你測量下體溫,本來是在小區門口測的,因為你進來,我就追著你進來。」
  • 植物大戰殭屍2:黑暗時代過關攻略,黑暗時代第十天簡單過關攻略
    那麼黑暗時代第十天怎麼過關?下面一起來看看黑暗時代第十天過關攻略~黑暗時代第10天簡單模式過關條件:利用從傳送帶上獲得的植物,抵擋殭屍的入侵查看更多這個關卡相對比較簡單,玩家根據選定植物抵擋殭屍入侵,大噴菇可以考慮放置在第一、二、三排,而菜問作為近身植物,可放置在五、六排(根據個人喜好,不過不建議放置在前面幾排),在菜問面前放置堅果,防止菜問被血量高的殭屍吃掉。玩家們記得種植土豆地雷。
  • 通達信:電腦端指標導入、源碼的寫入、看盤模板保存(詳細圖文)
    重點提示:總共3個部份,導入+源碼寫入+看盤模板編輯第一部分:導入
  • (附各類石材護理工程合同模板)
    其中:1、口頭契約:最簡潔的契約方式,缺點是沒有依據,無法受第三方監督,遇到問題很難證明契約的真實性,不利於保護雙方的權利。2、合作協議:雙方為委託與被委託關係,協議內容簡單、籠統,只涉及到雙方合作原則方面的東西,細節表述不足,協議也是受法律保護的。
  • 專利:裝配式免拆模板的應用技術
    說到免拆模板,很多朋友應該是比較陌生的,因為日常生活中,不是隨處可見,並不是說免拆模板應用的比較少
  • 原創模板:365存錢計劃表(鑽石版),讓存錢變得更有趣
    它把365天存款單元格剛剛好設計成了一個心形(當然仔細看的話,會發現作圖的時候有失誤,兩邊不對稱)。 此圖的使用方法是——每天強制自己存一筆錢,存款後,就在相應的格子上設置一個顏色。持之以恆,一年後你就能喜提一大筆錢。
  • 復仇者聯盟 | 為了做這個PPT模板,我等了10年
    我們做了一套復仇者主題免費模板4位設計師加入歷時7天,168小時超過100頁設計初稿少囉嗦,先看東西模板存放在 AbleSlide 的公眾號中,掃碼回復關鍵詞即可: 復仇者聯盟 為了致敬漫威,我們在模板裡也藏了無數彩蛋。如果你有幸找到彩蛋,有可能會發生意想不到的事情喔~~比如……》你可能會解鎖我們從沒公開過的模板頁面:
  • 民意測評問卷調查《問卷調查模板》
    所以即使提出了付費牆的商業模式,從新聞專業主義的角度來說,這種方式還有待商榷。民意測評問卷調查《問卷調查模板》