摘要:先推薦一個我自己寫的模板引擎,項目地址。下面就是總結(jié)的編寫模板引擎的幾個步驟例如一個模板為最終會編譯成為一個函數(shù)可以觀察到模板中的所有的變量名都被指定成了參數(shù)對象的屬性,并且該函數(shù)自始至終只做了一件事,就是構(gòu)建字符串,并將其返回。
先推薦一個我自己寫的模板引擎catpl,項目地址:https://github.com/liyu365/catpl。
項目中有詳細(xì)的注釋,代碼易讀,本項目借鑒自artTemplate、juicer、laytpl等諸多項目,在學(xué)習(xí)這些項目的過程中編寫而成,并遵守以下幾個步驟,可以對照此項目代碼進行了解。
例如一個模板為:
<%= title %>
最終會編譯成為一個函數(shù):
function anonymous($data, $methods) { var title = $data.title, sports = $data.sports, $escape = $methods.$escape; var $out = ""; $out += ""; $out += $escape(title); $out += "
可以觀察到模板中的所有的變量名都被指定成了參數(shù)$data對象的屬性,并且該函數(shù)自始至終只做了一件事,就是構(gòu)建$out字符串,并將其返回。下面來梳理一下將模板編譯為函數(shù)的過程:
步驟1. 確立模板中邏輯表達式的openTag和closeTag在上面的例子中<%和%>就是openTag和closeTag。
任何的HTML模板都包括兩個部分:
HTML語句
邏輯表達式語句
openTag和closeTag的作用就是劃分出這兩個部分區(qū)別對待。<%和%>包裹著的為邏輯表達式語句,在其之外的是普通的HTML語句。
步驟2. 拆分"HTML語句"和"邏輯表達式語句"methods.$foreach(source.split(options.openTag), function (code) { var arr = code.split(options.closeTag); if (arr.length === 1) { code_body += handle_html(arr[0]); } else { code_body += handle_logic(arr[0]); if (arr[1]) { code_body += handle_html(arr[1]); } } });
可以看到這一步利用openTag和closeTag把模板源碼中的HTML語句傳給了handle_html()函數(shù),把邏輯表達式語句傳給了handle_logic()函數(shù)。這兩個函數(shù)會把返回的代碼拼接給一個統(tǒng)一的變量。
步驟3. 處理模板中的"HTML語句"對應(yīng)上面提到的handle_html()函數(shù)。
這一步很好理解,只要原樣輸出就好。
步驟4. 處理模板中的"邏輯表達式語句"對應(yīng)上面提到的handle_logic()函數(shù),這一步的核心就是分析邏輯表達式語句中的變量名,函數(shù)名,識別的方式很簡單,只要不是js中的關(guān)鍵字、保留字都視為是一個變量名。
邏輯表達式語句又分為兩種:
1)賦值語句,形如<%= title %>。
直接把title視為是一個變量名,在函數(shù)的開始處聲明title為$data.title的引用。然后對title這個字符串原樣輸出。因為$data.title對應(yīng)的值可能帶有html中的特殊字符,所以在title外面包裹了$escape函數(shù)的調(diào)用。$escape函數(shù)是一個我們預(yù)先編寫好的函數(shù),存放在methods對象中,然后傳和data一樣傳入到編譯函數(shù)中。
2) 邏輯控制語句,形如for(var i = 0 ; i < sports.length ; i++ ) {
依然要分析變量名,例如這里的sports,注意分析變量名時一定要忽略.length這樣的對象屬性。
步驟5.生成編譯函數(shù)利用Function構(gòu)造函數(shù)生成一個函數(shù):
var fun = new Function("$data", "$method", code);
這里的code當(dāng)然就是handle_html()和handle_logic()兩個方法翻譯后的標(biāo)準(zhǔn)js代碼拼接而成的。
fun函數(shù)還需要進一步封裝,畢竟$method還沒有值。第四部已經(jīng)提到,methods其實是我們模板引擎內(nèi)部的對象,存放一些模板引擎的工具方法,我們應(yīng)該自己把它傳給編譯好的函數(shù)。其實給模板引擎注冊helper方法也是一樣的,需要我們自己把helper對象傳進編譯函數(shù)。包裝代碼如下:
return function (data) { return fun(data, methods, helpers); };
此時返回的函數(shù)就是用戶實際拿到的函數(shù)。
步驟6.進一步優(yōu)化"邏輯表達式語句"的語法其實做到第五步已經(jīng)是一個具備基本功能的模板引擎了,但是模板中邏輯表達式不夠簡潔,例如:
<% for(var i = 0 ; i < sports.length ; i++ ) { %>
這種表達式其實還是原生的js語法,我們可以自己定義模板引擎的語法,例如:
<% foreach sports %>
這其實不難做到,只是在第四部開始之前利用正則把foreach sports再變?yōu)?b>for(var i = 0 ; i < sports.length ; i++ ) {,之后還是一樣的流程。
catpl項目中有一個options.syntax_hook方法就是用來定義自己的模板語法的,可以將options.syntax_hook的值設(shè)為null來在自定義語法和原生js語法之間切換。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/80918.html
對于了解Node的開發(fā)人員,我們都知道Node是基于Chrome V8引擎開發(fā)的能使JavaScript在服務(wù)器端運行的運行時環(huán)境(runtime environment)。一方面,它提供了多種可調(diào)用的API,如讀寫文件、網(wǎng)絡(luò)請求、系統(tǒng)信息等。另一方面,因為CPU執(zhí)行的是機器碼,它還負(fù)責(zé)將JavaScript代碼解釋成機器指令序列執(zhí)行,這部分工作是由V8引擎完成。 Motivation JavaS...
摘要:由于這些是驅(qū)動的工具,因此它們由引擎提供支持。兩個主要引擎是的和的引擎。然后,四個即時進程啟動,分析并執(zhí)行解析器生成的字節(jié)碼。簡單來說,這個引擎獲取源代碼,將其分解為字符串,獲取這些字符串并將它們轉(zhuǎn)換為編譯器可以理解的字節(jié)碼,然后執(zhí)行它。 渲染引擎和JavaScript引擎 先從一張圖片來理解下這兩個引擎 showImg(https://segmentfault.com/img/bVb...
摘要:由于這些是驅(qū)動的工具,因此它們由引擎提供支持。兩個主要引擎是的和的引擎。然后,四個即時進程啟動,分析并執(zhí)行解析器生成的字節(jié)碼。簡單來說,這個引擎獲取源代碼,將其分解為字符串,獲取這些字符串并將它們轉(zhuǎn)換為編譯器可以理解的字節(jié)碼,然后執(zhí)行它。 渲染引擎和JavaScript引擎 先從一張圖片來理解下這兩個引擎 showImg(https://segmentfault.com/img/bVb...
摘要:由于這些是驅(qū)動的工具,因此它們由引擎提供支持。兩個主要引擎是的和的引擎。然后,四個即時進程啟動,分析并執(zhí)行解析器生成的字節(jié)碼。簡單來說,這個引擎獲取源代碼,將其分解為字符串,獲取這些字符串并將它們轉(zhuǎn)換為編譯器可以理解的字節(jié)碼,然后執(zhí)行它。 渲染引擎和JavaScript引擎 先從一張圖片來理解下這兩個引擎 showImg(https://segmentfault.com/img/bVb...
閱讀 3205·2021-11-08 13:21
閱讀 1195·2021-08-12 13:28
閱讀 1406·2019-08-30 14:23
閱讀 1924·2019-08-30 11:09
閱讀 840·2019-08-29 13:22
閱讀 2684·2019-08-29 13:12
閱讀 2549·2019-08-26 17:04
閱讀 2250·2019-08-26 13:22