javascript模板系統 ejs v10

來源:互聯網
上載者:User

最近一直攻略node.js,發現ejsv9在後端的視圖層有點力不從心。

後端是模板的最大使用者,因此拼字串必須會死翹翹。通常來說,我們一個action對應一個模板,它應該是只含body部分的HTML,另外,還有一個layout,它是包含head與body的底部。它們兩個加起來,加個模型層的資料產生一個真正的頁面返給前端。但產生這頁面不像普通的挖坑填數位過程,像ejs、mustache、micro-Templating、doT.js就是如此。不過有的模板可以套嵌大量的邏輯,有的不能,像mustache就號稱Logic-less templates,目的不想讓模板也成為代碼的意大利麵條,這是JSP時代的教訓。但javaer在struct建立王者統治的年代,騰出許多精力來研究各種東西,對視圖層提出兩大解決方案,視圖helper與標籤庫。其中標籤庫因為學習成本過高,因此當其他語言發展出的web framework時,視圖helper幾乎是他們唯一的選擇。視圖helper也是返回一段HTML字串,只不過它與業務層打交道非常頻繁而獨立出來,而它們獨立出來則大大減少視圖亂堆代碼的現象。helper機制就是ejs v10引入的一種重要改進了。

另外,模板裡面的內容有兩個地方需要輸出到頁面,一個是定界符左邊與右邊的HTML片斷,另一個是來自JS邏輯的某些資料,如&lt%= aaa %>這樣的寫法(不同每個模板的文法都不一樣!)PHP著名的smarty模板有個文法糖,可以對這些將要輸出的變數進行進一步加工,即在變數後面加一個|號,後面跟著此過濾器的名字與其傳參,而且可以跟多個|跟其他的過濾器。ejs v10也引進此文法糖。


在其他重大改進,模板構建演算法改進,不再使用轉義。傳統的前端模板都會對源碼中的“'”,“"”,“\\”,“\n”,“\t”,“\f”,“\b”,“\r”進行處理,也就是所謂加雙號過程,雙引號裡面的資料進行轉義,防止破壞動態產生的模板函數的結構。ejs v10則將這個HTML數組放到模板函數的外面,從此一勞永逸了!@首碼變數也保證ejs不使用with機制進行對象綁定的。

helper機制的使用,helper函數應該一開始就與模板函數綁在一起的,因此ejs v10的模板函數最初是一個curry函數,它負責傳入HTML數組,filter,與helpers。

//helper機制的使用 var fn = $.ejs.compile(source, helper);

helper是一個對象,裡面儘是函數。

產生的是模板函數,如果你是這樣調用$.ejs(id, data),它就百分之百緩衝了這函數。它裡面是調用了$.ejs.compile

現在ejs作為我的newland.js項目的一個模組而存在.

變更記錄檔:

v1預設界定符為,當然也可以自訂界定符,只支援當前頁面的script元素做模板http://www.cnblogs.com/rubylouvre/archive/2010/08/10/1796383.htmlv2改進構建演算法提速,比John Resig的 Micro-Templating模板更能應對複雜的模板http://www.cnblogs.com/rubylouvre/archive/2010/08/22/1805914.htmlv3http://www.cnblogs.com/rubylouvre/archive/2010/08/25/1807789.html增添了局部模板功能v4http://www.cnblogs.com/rubylouvre/archive/2010/08/31/1813122.html對v3的結構進行最佳化,支援遠端獨立檔案做模板v5http://www.cnblogs.com/rubylouvre/archive/2010/08/31/1813122.html嘗試新的演算法v6http://www.cnblogs.com/rubylouvre/archive/2010/10/05/1841933.html更新預設界定符為,添加新的操作符

我已經整成jQuery外掛程式了,隨便拿去用吧!點我下載

            ;;(function($){                // by 司徒正美                //http://www.cnblogs.com/rubylouvre/archive/2012/08/06/2624970.html                /**                 * 入口函數                 * @param {string} id CSS運算式(用於模取元素然後取得裡面的innerHTML作為源碼)                 * @param {Object} data  資料包                 * @return  {Object} opts 選擇性參數,可以自由制定你的定界符                 */                $.ejs = function( id,data,opts){                    var el, source                    if( !$.ejs.cache[ id] ){                        opts = opts || {}                        var doc = opts.doc || document;                        data = data || {};                        el = $(id, doc)[0];                        if(! el )                            throw "can not find the target element";                        source = el.innerHTML;                        if(!(/script|textarea/i.test(el.tagName))){                            source = $.ejs.filters.unescape( source );                        }                        var fn = $.ejs.compile( source, opts );                        $.ejs.cache[ id ] = fn;                    }                    return $.ejs.cache[ id ]( data );                }                var isNodejs = typeof exports == "object";                $.ejs.cache = {};                $.ejs.filters = {                    //自己可以在這裡添加更多過濾器,或者可以到這裡面自由提取你喜歡的工具函數                    //https://github.com/RubyLouvre/newland/blob/master/system/lang.js                    escape:  function (target) {                        return target.replace(/&/g,'&amp;')                        .replace(/</g,'&lt;')                        .replace(/>/g,'&gt;')                        .replace(/"/g, """)                        .replace(/'/g, "'");                    },                    unescape: function(target){                        return  target.replace(/"/g,'"')                        .replace(/</g,'')                        .replace(/&/g, "&"); //處理轉義的中文和實體字元                        return target.replace(/([\d]+);/g, function($0, $1){                            return String.fromCharCode(parseInt($1, 10));                        });                    }                };                $.ejs.compile = function( source, opts){                    opts = opts || {}                    var open  = opts.open  || isNodejs ? "" : "&>";                    var helperNames = [], helpers = []                    for(var name in opts){                        if(opts.hasOwnProperty(name) && typeof opts[name] == "function"){                            helperNames.push(name)                            helpers.push( opts[name] )                        }                    }                    var flag = true;//判定是否位於前定界符的左邊                    var codes = []; //用於放置源碼模板中普通文本片斷                    var time = new Date * 1;// 時間截,用於構建codes數組的引用變數                    var prefix = " ;r += txt"+ time +"[" //渲染函數輸出部分的前面                    var postfix = "];"//渲染函數輸出部分的後面                    var t = "return function(data){ try{var r = '',line"+time+" = 0;";//渲染函數的最開始部分                    var rAt = /(^|[^\w\u00c0-\uFFFF_])(@)(?=\w)/g;                    var rstr = /(['"])(?:\\[\s\S]|[^\ \\r\n])*?\1/g                     var rtrim = /(^-|-$)/g;                    var rmass = /mass/                    var js = []                    var pre = 0, cur, code, trim                    for(var i = 0, n = source.length; i  1 ){//使用過濾器                                        var arr = []                                        var str = code.replace(rstr, function(str){                                            arr.push(str);//先收拾所有字串字面量                                            return 'mass'                                        }).replace(/\|\|/g,"@");//再收拾所有短路或                                        if(str.indexOf("|") > 1){                                            var segments = str.split("|")                                            var filtered = segments.shift().replace(/\@/g,"||").replace(rmass, function(){                                                return arr.shift();                                            });                                            for( var filter;filter = arr.shift();){                                                segments = filter.split(":");                                                name = segments[0];                                                args = "";                                                if(segments[1]){                                                    args = ', ' + segments[1].replace(rmass, function(){                                                        return arr.shift();//還原                                                    })                                                }                                                filtered = "$.ejs.filters."+ name +"(" +filtered + args+")"                                            }                                            code = "="+ filtered                                        }                                    }                                    t += " ;r +" +code +";"                                    break;                                case "#"://注釋,不輸出                                    break                                case "-":                                default://普通邏輯,不輸出                                    code = code.replace(rtrim,function(){                                        trim = true;                                        return ""                                    });                                    t += code.replace(rAt,"$1data.")                                    break                            }                            i = cur + close.length;                        }                        flag = !flag;                    }                    t += " return r; }catch(e){ $.log(e);\n$.log(js"+time+"[line"+time+"-1]) }}"                    var body = ["txt"+time,"js"+time, "filters"]                    var fn = Function.apply(Function, body.concat(helperNames,t) );                    var args = [codes, js, $.ejs.filters];                    //console.log(fn+"")                    return fn.apply(this, args.concat(helpers));                }                return $.ejs;            })(jQuery)


<script type="tmpl" id="table_tmpl">        <&= title() &>        <table border=1>        <&- for(var i=0,tl = @trs.length,tr;i<tl;i++){  -&>            <&- tr = @trs[i]; -&>            <tr>            <td><&= tr.name;; &></td> <td><&= tr.age; &></td> <td><&= tr.sex || "男" &></td>            </tr>            <& } &>        </table>        < 怎麼可能不支援圖片 &>        <img src="<&= @href &>"></script><script>              $(function(){        var trs = [            {name:"隱形殺手",age:29,sex:"男"},            {name:"索拉",age:22,sex:"男"},            {name:"fesyo",age:23,sex:"女"},            {name:"戀妖壺",age:18,sex:"男"},            {name:"竜崎",age:25,sex:"男"},            {name:"你不懂的",age:30,sex:"女"}        ]        var html = $.ejs("#table_tmpl",{            trs: trs,            href: "http://images.cnblogs.com/cnblogs_com/rubylouvre/202906/o_type4.jpg"        },{            title: function(){                return "<p>這是使用視圖helper輸出的代碼片斷</p>"            }                           });        $("#ejsv10").html(html)    })</script>


輸出結果如下:

這是我模板引擎產生的函數,裡面看不到要轉義的字串!

相關文章

聯繫我們

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