編寫一個簡單的JavaScript模板引擎<轉>

來源:互聯網
上載者:User

標籤:https   運算式   定義   過程   nbsp   javascrip   tar   自己的   ddl   

轉自:廖雪峰  https://www.liaoxuefeng.com/article/001426512790239f83bfb47b1134b63b09a57548d06e5c5000

 

隨著Nodejs的流行,JavaScript在前端和後端都開始流行起來。有許多成熟的JavaScript模板引擎,例如Swig,既可以用在後端,又可以用在前端。

不過很多時候,前端模板僅僅需要簡單地建立一個HTML片段,用Swig這種全功能模板有點大材小用。我們來嘗試自己編寫一個簡單的前端模板引擎,實際上並不複雜。

在編寫前端模板引擎代碼之前,我們應該想好如何來調用它,即這個模板引擎的介面應該是什麼樣的。我們希望這樣調用它:

// 建立一個模板引擎:var tpl = new Template(‘<p>Today: { date }</p>\n<a href="/{ user.id|safe }">{ user.company }</a>‘);// 渲染得到HTML片段:var model = {    date: 20150316,    user: {        id: ‘A-000&001‘,        company: ‘AT&T‘    }};var html = tpl.render(model);console.log(html);// <p>Today: 20150316</p>// <a href="/A-000&001">AT&amp;T</a>

 

因此,一個模板引擎就是把一個字串中的變數用model的變數替換掉,就完成了。

像Swig這種類Jinja2的模板引擎,它可以替換{{ model.prop }}這樣的變數。

我們選用{ model.prop }來實現我們自己的變數替換,基本思想是用一個Regex來匹配{ xxx.xxx }

var re = /\{\s*([a-zA-Z\.\_0-9()]+)\s*\}/mvar match = re.exec(‘a { template } string‘);

 

如果正則匹配成功,則match不為空白,match[0]是匹配到的字串{ template }match[1]是捕獲的變數templatematch.index是匹配的索引。

只要不斷地匹配到變數,然後用model的內容替換,就可以得到最終的HTML。但是,分析user.addr.zipcode然後去model中尋找並不容易。而且,模板應該可以先行編譯,這樣,後續渲染速度就會很快。

JavaScript允許用new Function(‘source‘)來通過字串建立一個函數,這個函數和我們用function ()定義的函數是一模一樣的,因此,一個模板引擎的編譯過程就是建立一個函數,然後調用該函數就實現了模板渲染。

需要編譯的函數代碼應該像這樣:

function () {    var r = [];    r.push(‘<p>Today: ‘);    r.push(this.date);    r.push(‘</p>\n<a href="/‘);    r.push(this.user.id);    r.push(‘">‘);    r.push(this.user.company);    r.push(‘</a>‘);    return r.join(‘‘);}

 

注意到變數名從variable.prop變成了this.variable.prop,是因為調用該函數時我們會把model綁定到this變數上。

因此,模板引擎的代碼如下:

function Template(tpl) {    var        fn,        match,        code = [‘var r=[];‘],        re = /\{\s*([a-zA-Z\.\_0-9()]+)\s*\}/m,        addLine = function (text) {            code.push(‘r.push(\‘‘ + text.replace(/\‘/g, ‘\\\‘‘).replace(/\n/g, ‘\\n‘).replace(/\r/g, ‘\\r‘) + ‘\‘);‘);        };    while (match = re.exec(tpl)) {        if (match.index > 0) {            addLine(tpl.slice(0, match.index));        }        code.push(‘r.push(this.‘ + match[1] + ‘);‘);        tpl = tpl.substring(match.index + match[0].length);    }    addLine(tpl);    code.push(‘return r.join(\‘\‘);‘);    // 建立函數:    fn = new Function(code.join(‘\n‘));    // 用render()調用函數並綁定this參數:    this.render = function (model) {        return fn.apply(model);    };}

 

現在,這個簡單的模板引擎已經可以工作了。但是它還有幾個小問題需要解決,一是預設的變數在替換時應該做HTML轉義,二是如果某些不需要轉義的變數,可以用{ user.id|safe }這樣的運算式表示user.id無需轉義。

經過HTML轉義和{ variable|safe }處理的最終代碼如下:

function Template(tpl) {    var        fn,        match,        code = [‘var r=[];\nvar _html = function (str) { return str.replace(/&/g, \‘&amp;\‘).replace(/"/g, \‘&quot;\‘).replace(/\‘/g, \‘&#39;\‘).replace(/</g, \‘&lt;\‘).replace(/>/g, \‘&gt;\‘); };‘],        re = /\{\s*([a-zA-Z\.\_0-9()]+)(\s*\|\s*safe)?\s*\}/m,        addLine = function (text) {            code.push(‘r.push(\‘‘ + text.replace(/\‘/g, ‘\\\‘‘).replace(/\n/g, ‘\\n‘).replace(/\r/g, ‘\\r‘) + ‘\‘);‘);        };    while (match = re.exec(tpl)) {        if (match.index > 0) {            addLine(tpl.slice(0, match.index));        }        if (match[2]) {            code.push(‘r.push(String(this.‘ + match[1] + ‘));‘);        }        else {            code.push(‘r.push(_html(String(this.‘ + match[1] + ‘)));‘);        }        tpl = tpl.substring(match.index + match[0].length);    }    addLine(tpl);    code.push(‘return r.join(\‘\‘);‘);    fn = new Function(code.join(‘\n‘));    this.render = function (model) {        return fn.apply(model);    };}

 

現在就可以用我們預設的代碼來使用這個模板引擎了。不過,把模板寫在字串中也不是一個好辦法。最佳解決方案是利用<script>標籤,把模板寫在裡面,注意一定要加上type="text/plain"

<script id="tpl" type="text/plain">    <p>Today: { date }</p>    <a href="/{ user.id|safe }">{ user.company }</a></script>

 

然後,用jQuery來獲得模板內容並渲染:

var tpl = new Template($(‘#tpl‘).html());var s = tpl.render({    date: 20150101,    user: {        id: ‘A-000&001‘,        company: ‘AT&T‘    }});$(‘#other‘).html(s);

 

這樣,我們就用不到30行代碼實現了一個簡單的JavaScript模板引擎。

編寫一個簡單的JavaScript模板引擎<轉>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.