javascript編寫自己的模板解析器

來源:互聯網
上載者:User

javascript編寫自己的模板解析器
編寫自己的模板解析器

因為最近在研究artTemplate,ejs,baaiduTemplate等模板,所以,一時興起,自己也寫了個簡單的模板解析器。

一個最基本的模板解析器,需要有什麼功能呢?

讀取變數值 解析模板語句

按照這個思路,我們編寫一個簡單的解析器,需求如下:

讀值: <%= 變數名 %> 語句支援: <% if( type == 1 ){ %> good! <%}%>

總體來說,就是如果模板如下:

我叫:<%= name %> <% if(type == 1){ %>    狀態: <%= type %><% } %>

如果有資料{name: ‘da宗熊’ type: 1},則需要輸出:

我叫: da宗熊狀態: good!

按照上面需求,我們需要做什麼呢?因為考慮到要在模板內執行指令碼,所以,最直接的辦法, 就是把模板翻譯為 javascript。

動手咧變數

觀看了上面幾個模板引擎的代碼,主要思路莫過於:

通過正則匹配,找出 ‘<%…%>’ 的模組,進行處理 把所有匹配出來的內容,拼接為 字串 然後通過 new Function 產生可執行檔函數

但3者,對於 <%= 變數 %> 的取值,有著不同的處理:

ejs通過with語句,給變數指定了變數的訪問上下文。

artTemplate和baiduTemplate通過遍曆傳入的變數,產生變數聲明語句,從而達到給變數賦值的效果。

考慮到with語句的低效,這裡採取了 第二種 形式。

// 如有傳入的變數參數為:datavar data = {    name: 'da宗熊', type: 1};// 那模板中,遍曆變數,產生聲明語句var varStatement = '';for(var name in data){    varStatement += 'var ' + name +' = data.' + name + ';';}// varStatement = 'var name = data.name;var type = data.type;';
函數

第二部,也是最重要的,莫屬於解析模板的語句了。

因為模板,經常會是某個元素的innerHTML,而它的換行[呃,我不擅長控制],一般我會替換掉:

<script>    var html = template.innerHTML;    // 替換掉換行:    html = html.replace(/s/g,  );</script>

考慮到, ‘xx內容<% 運算式 %>’ 這種形式比較好用正則匹配,所以,把 ‘前面內容<%運算式%>後面內容’ 的 ‘前面’ 和 ‘後面’ 部分去掉:

// resList 是最終的結果,rightContent是‘後面’部分的內容var resList = [], rightContent = '';html = html.replace(/(.*?)(<%.*%>)(.*)/g, function(str, left, center, right){    rightContent = right;    resList.push(left);    console.log(left:%s center:%s right:%s, left, center, right);    return center;});// 正則匹配的內容將是:// left: 我叫:// center: <%= name %>     <% if(type == 1){ %>        狀態: <%= type %> <% }%>// right: 

剩下 ‘center’ 的內容,都符合 ‘xx內容<%運算式%>’ 的格式,所以,使用正則,編譯剩下的內容:

var __TMP_LIST__ = '__TMP_LIST__',    __TMP_DATA__ = '__TMP_DATA__';// 需要編譯的動態函數內容var fnStr = '';// 開始匹配運算式,匹配 'xxx<% expr %>'html.replace(/(.*?)<%(.*?)%>/g, function(str, html, exp){    console.log(html:%s exp:%s, html, exp);    // html內容    fnStr += __TMP_LIST__ + .push(' + quote(html) + ');;    // 運算式內容,帶等號,取值,不帶,則是動態函數的邏輯控制部分    if(exp.indexOf(=) === 0){        fnStr += __TMP_LIST__ + .push(+ exp.slice(1) +);;    }else{        fnStr += exp;    }});
產生動態函數

準備工作都完成了,剩下最後一步:

// 構建編譯的動態函數var fn = new Function(__TMP_DATA__, __TMP_LIST__, fnStr);// 如果結果清單沒有資料,則沒有需要編譯的內容if(resList.length > 0){    // 把需要編譯的資料,結果清單,傳入動態函數    fn(data, resList);    // 不要漏了最後一個小尾巴,上面去除 ‘前’ 和 ‘後’部分,留下的    resList.push(rightContent);    console.log(resList.join());}else{    console.log(html);}

一個簡答的模板編譯函數,已經大功告成了~。

最後

最除版本,肯定有很多BUG,不過思路應該沒有錯的。還有挺多拓展的,像轉義,錯誤偵測什麼的,配置定界符什麼的,都可以嘗試,這裡就不再詳細介紹了。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.