javascript模板系統 ejs v3

來源:互聯網
上載者:User

本版本增添了局部模板功能,並且允許主模板調用局部模板,局部模組調用局部模組,並去掉onsite變數,不再提供解析成畢的文檔片段給使用者。它使用雙重緩衝,一是緩衝那些通過同步請求得到的文本而成的數組,一是整體解析完畢得到的模板函數。模板函數是通過數組元素拼湊動成解析而成的,這是大大提高了效率。不過由於新功能的加入,雖然動用了新的構築演算法也比不上v2的構築速度了……

有人說不要使用<%與%>做界定符,這個問題我在v1版本已經提出過了,這些都是可以自訂的。本文的例子將示範一下如何使用Django的{{與}}風格。

最後隆重推介一下本版本的新功能。不過由於條件有限,無法示範。現在模板不單單是內嵌於頁面的script標籤之內,也可以放置在一個獨立的檔案之內,如html,ejs,text,隨你起什麼尾碼名。這個檔案將會用同步請求回來用於構築模板函數。我們可以用使用url屬性,或在模板中使用<%: /template/partail.ejs >實現。一般而言,url是用於主模板,而<%: url %>是用於局部模板。如果我們在設定物件中同時使用selector與url,selector的優先順序是高於url的。

   var data = dom.ejs({                    selector:"tmpl",                    url:"/template/aaa.html",                    left:"{{",                    right:"}}",                    json: {                        name:"司徒正美",                        blog:"ruby louvre"                        address:"異次元"                    }     });

源碼:

//司徒正美 javascript template - http://www.cnblogs.com/rubylouvre/ - MIT Licensed            (function () {                if(!String.prototype.trim){                    String.prototype.trim = function(){                        return this.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');                    }                }                var dom = {                    quote: function (str) {                        str = str.replace(/[\x00-\x1f\\]/g, function (chr) {                            var special = metaObject[chr];                            return special ? special : '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4)                        });                        return '"' + str.replace(/"/g, '\\"') + '"';                    }                },                metaObject = {                    '\b': '\\b',                    '\t': '\\t',                    '\n': '\\n',                    '\f': '\\f',                    '\r': '\\r',                    '\\': '\\\\'                },                startOfHTML = "\t__views.push(",                endOfHTML = ");\n";                (function(){                    //http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx                    var s = ["XMLHttpRequest",                        "ActiveXObject('Msxml2.XMLHTTP.6.0')",                        "ActiveXObject('Msxml2.XMLHTTP.3.0')",                        "ActiveXObject('Msxml2.XMLHTTP')",                        "ActiveXObject('Microsoft.XMLHTTP')"];                    if( eval("''+/*@cc_on"+" @_jscript_version@*/-0")*1 === 5.7 && location.protocol === "file:"){                        s.shift();                    }                    for(var i = 0 ,el;el=s[i++];){                        try{                            if(eval("new "+el)){                                dom.xhr = new Function( "return new "+el)                                break;                            }                        }catch(e){}                    }                })();                dom.partial = function(url){                    var xhr = dom.xhr();                    xhr.open("GET",url,false);                    xhr.setRequestHeader("If-Modified-Since","0");                    xhr.send(null);                    return xhr.responseText|| ""                }                dom.tmpl = function(str,rLeft,rRight,sRight){                    var arr = str.trim().split(rLeft),self = arguments.callee,buff = [],url,els,el,i = 0, n= arr.length;                    while (i<n) {                        els = arr[i++]; el = els.split(rRight);                        if(els.indexOf(sRight) !== -1){//這裡不使用els.length === 2是為了避開IE的split bug                            switch (el[0].charAt(0)) {                                case "#"://處理注釋                                    break;                                case "="://處理後台返回的變數(輸出到頁面的);                                    buff.push(startOfHTML, el[0].substring(1), endOfHTML)                                    break;                                case ":"://處理局部模板                                    url = el[0].substring(1).trim();                                    //緩衝構築函數的數組                                    self[url] = self[url] || self.call(null,dom.partial(url),rLeft,rRight,sRight);                                    buff = buff.concat(dom.tmpl[url] );                                    break;                                default:                                    buff.push(el[0], "\n");                            };                            el[1] &&  buff.push(startOfHTML, dom.quote.call(null,el[1]), endOfHTML);                        }else{                            buff.push(startOfHTML, dom.quote.call(null,el[0]), endOfHTML);                        }                    }                    return buff;                }                dom.ejs = function (obj) {                    var sLeft = obj.left || "%>",                    sRight = obj.right || "<%",                    rLeft = new RegExp("\\s*"+sLeft+"\\s*"),                    rRight = new RegExp("\\s*"+sRight+"\\s*"),                    buff = ["var __views = [];\n"],                    key = obj.selector || obj.url,str;                    if(obj.selector){                        var el = document.getElementById(key);                        if (!el) throw "找不到目標元素";                        str = el.text;                    }else{                        str =  dom.partial(key);                        if(!str) throw "目標檔案不存在";                    }                    if(!dom.tmpl[key]){//緩衝模板函數                        buff = buff.concat(dom.tmpl.call(null,str,rLeft,rRight,sRight));                        dom.tmpl[key] = new Function("json", "with(json){"+buff.join("") + '\t};return __views.join("");');                    }                    return dom.tmpl[key](obj.json || {});                };                window.dom = dom;            })();

樣本:

<!doctype html><html>    <head>        <meta charset="utf-8"/>        <meta content="IE=8" http-equiv="X-UA-Compatible"/>        <meta name="keywords" content="javascript模板 by 司徒正美" />        <meta name="description" content="javascript模板 by 司徒正美" />        <title>javascript模板 by 司徒正美</title>    </head>    <body>        <h1>javascript模板 by 司徒正美</h1>        <div id="tmplTC">這是容器</div>        <script id="tmpl" type="tmpl">                <h2>{{=  name }}{{= name }}</h2>                {{# 這是注釋!!!!!!!!! }}                <ul>                {{ for(var i=0; i< uls.length; i++){ }}                    <li>{{=  uls[i] }}的名字是{{= name }}</li>                    {{  }  }}                </ul>                {{ var color = "color:red;" }}                <p style="text-indent:2em;{{= color }} ">{{= address }}</p>                   </script>       <script src="dom/ejs.js"></script&gt        <script>            window.onload = function(){                var els = [];                for(var i=0;i<1000;i++){                    els.push("第"+i+"個元素")                }                var a = new Date                var data = dom.ejs({                    selector:"tmpl",                    left:"{{",                    right:"}}",                    json: {                        name:"司徒正美",                        uls:els,                        address:"異次元"                    }                });                document.getElementById("tmplTC").innerHTML = data;                alert( new Date-a)            }        </script>    </body></html>

<br /><!doctype html><br /><html><br /> <head><br /> <meta charset="utf-8"/><br /> <meta content="IE=8" http-equiv="X-UA-Compatible"/><br /> <meta name="keywords" content="javascript模板 by 司徒正美" /><br /> <meta name="description" content="javascript模板 by 司徒正美" /><br /> <title>javascript模板 by 司徒正美</title><br /> </head><br /> <body><br /> <h1>javascript模板 by 司徒正美</h1><br /> <div id="tmplTC">這是容器</div><br /> <script id="tmpl" type="tmpl"><br /> <h2>{{= name }}{{= name }}</h2><br /> {{# 這是注釋!!!!!!!!! }}<br /> <ul><br /> {{ for(var i=0; i< uls.length; i++){ }}<br /> <li>{{= uls[i] }}的名字是{{= name }}</li><br /> {{ } }}<br /> </ul><br /> {{ var color = "color:red;" }}<br /> <p style="text-indent:2em;{{= color }} ">{{= address }}</p></p><p> </script></p><p> <script><br /> (function () {</p><p> if(!String.prototype.trim){<br /> String.prototype.trim = function(str){<br /> return this.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');<br /> }<br /> }<br /> var dom = {<br /> quote: function (str) {<br /> str = str.replace(/[\x00-\x1f\\]/g, function (chr) {<br /> var special = metaObject[chr];<br /> return special ? special : '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4)<br /> });<br /> return '"' + str.replace(/"/g, '\\"') + '"';<br /> }<br /> },<br /> metaObject = {<br /> '\b': '\\b',<br /> '\t': '\\t',<br /> '\n': '\\n',<br /> '\f': '\\f',<br /> '\r': '\\r',<br /> '\\': '\\\\'<br /> },<br /> startOfHTML = "\t__views.push(",<br /> endOfHTML = ");\n";<br /> (function(){<br /> //http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx<br /> var s = ["XMLHttpRequest",<br /> "ActiveXObject('Msxml2.XMLHTTP.6.0')",<br /> "ActiveXObject('Msxml2.XMLHTTP.3.0')",<br /> "ActiveXObject('Msxml2.XMLHTTP')",<br /> "ActiveXObject('Microsoft.XMLHTTP')"];<br /> if( eval("''+/*@cc_on"+" @_jscript_version@*/-0")*1 === 5.7 && location.protocol === "file:"){<br /> s.shift();<br /> }<br /> for(var i = 0 ,el;el=s[i++];){<br /> try{<br /> if(eval("new "+el)){<br /> dom.xhr = new Function( "return new "+el)<br /> break;<br /> }<br /> }catch(e){}<br /> }<br /> })();</p><p> dom.partial = function(url){<br /> var xhr = dom.xhr();<br /> xhr.open("GET",url,false);<br /> xhr.setRequestHeader("If-Modified-Since","0");<br /> xhr.send(null);<br /> return xhr.responseText|| ""<br /> }</p><p> dom.tmpl = function(str,rLeft,rRight,sRight){<br /> var arr = str.trim().split(rLeft),self = arguments.callee,buff = [],url,els,el,i = 0, n= arr.length;<br /> while (i<n) {<br /> els = arr[i++]; el = els.split(rRight);<br /> if(els.indexOf(sRight) !== -1){//這裡不使用els.length === 2是為了避開IE的split bug<br /> switch (el[0].charAt(0)) {<br /> case "#"://處理注釋<br /> break;<br /> case "="://處理後台返回的變數(輸出到頁面的);<br /> buff.push(startOfHTML, el[0].substring(1), endOfHTML)<br /> break;<br /> case ":"://處理局部模板<br /> url = el[0].substring(1).trim();<br /> self[url] = self[url] || self.call(null,dom.partial(url),rLeft,rRight,sRight);<br /> buff = buff.concat(dom.tmpl[url] );<br /> break;<br /> default:<br /> buff.push(el[0], "\n");<br /> };<br /> el[1] && buff.push(startOfHTML, dom.quote.call(null,el[1]), endOfHTML);<br /> }else{<br /> buff.push(startOfHTML, dom.quote.call(null,el[0]), endOfHTML);<br /> }<br /> }<br /> return buff;<br /> }</p><p> dom.ejs = function (obj) {<br /> var sLeft = obj.left || "%>",<br /> sRight = obj.right || "<%",<br /> rLeft = new RegExp("\\s*"+sLeft+"\\s*"),<br /> rRight = new RegExp("\\s*"+sRight+"\\s*"),<br /> buff = ["var __views = [];\n"],<br /> key = obj.selector || obj.url,str;<br /> if(obj.selector){<br /> var el = document.getElementById(key);<br /> if (!el) throw "找不到目標元素";<br /> str = el.text;<br /> }else{<br /> str = dom.partial(key);<br /> if(!str) throw "目標檔案不存在";<br /> }<br /> if(!dom.tmpl[key]){//以選取器-->解析函數的形式緩衝到dom.tmpl函數中<br /> buff = buff.concat(dom.tmpl.call(null,str,rLeft,rRight,sRight));<br /> dom.tmpl[key] = new Function("json", "with(json){"+buff.join("") + '\t};return __views.join("");');<br /> }<br /> return dom.tmpl[key](obj.json || {});<br /> };<br /> window.dom = dom;</p><p> })();</p><p> window.onload = function(){<br /> var els = [];<br /> for(var i=0;i<1000;i++){<br /> els.push("第"+i+"個元素")<br /> }<br /> var a = new Date<br /> var data = dom.ejs({<br /> selector:"tmpl",<br /> left:"{{",<br /> right:"}}",<br /> json: {<br /> name:"司徒正美",<br /> uls:els,<br /> address:"異次元"<br /> }<br /> });<br /> document.getElementById("tmplTC").innerHTML = data;<br /> alert( new Date-a)<br /> }<br /> </script><br /> </body><br /></html><br />

運行代碼

現在我有一個考量,就是隨著模板規模的膨脹,裡面可能夾雜著越來越多變數,我們就很難分辨得清那些後台傳過的東西,那些是本地的臨時變數,背景需求一變更,背景json資料也就要改動。這維護起來非常困難。因此我非常欣賞ruby的變數書寫風格,從變數名就知它是執行個體變數,類變數,普通變數與常量,它還有符號這東西呢,我會v4版本加入重新加入@標識符的。

相關文章

聯繫我們

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