• javascript模板系统 ejs v3


    本版本增添了局部模板功能,并且允许主模板调用局部模板,局部模块调用局部模块,并去掉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>
            <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>
    

    现在我有一个考量,就是随着模板规模的膨胀,里面可能夹杂着越来越多变量,我们就很难分辨得清那些后台传过的东西,那些是本地的临时变量,后台的需求一变更,后台的json数据也就要改动。这维护起来非常困难。因此我非常欣赏ruby的变量书写风格,从变量名就知它是实例变量,类变量,普通变量与常量,它还有符号这东西呢,我会v4版本加入重新加入@标识符的。

  • 相关阅读:
    升级python
    python内置函数整理
    import 搜索路径
    webpy 解决中文出现UnicodeDecodeError: 'ascii' codec can't decode byte 问题
    未预期的符号 `$'{ '' 附近有语法错误
    python引入模块时import与from ... import的区别
    "Native table 'performance_schema'.'session_variables' has the wrong structure") [SQL: "SHOW VARIABLES LIKE 'sql_mode'"]
    git命令
    Redis简介
    MongoDB基本操作
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1807789.html
Copyright © 2020-2023  润新知