位置:海鸟网 > IT > JavaScript >

javascript模板系统

由于各种原因,被逼使用前台模板。看了一下其他模板库的实现,发现其原理并不难,遂决定重造轮子。使用ROR.erb风格。换言之,逻辑是写在"<%"与"%>"之间,如果是注释,则用"<%#"与"%>",凡是后台传过来的变量都加上@来标记。现在这个模板系统还没有搭载任何helper方法,也不依赖任何代码,因此非常精短。

<!doctype html>
<html>
    <head>
        <title>postMessage by 司徒正美</title>
        <meta charset="utf-8"/>
        <meta content="IE=8" http-equiv="X-UA-Compatible"/>
        <meta name="keywords" content="t模板 by 司徒正美" />
        <meta name="description" content="javascript模板 by 司徒正美" />
        <title>javascript模板 by 司徒正美</title>
    </head>
    <body>
        <h1>javascript模板 by 司徒正美</h1>
        <textarea id="tmpl" style="display:none;" >
        <h2><%= @name %></h2>
        <%# 这是注释 %>
        <ul>
        <% for(var i=0; i<@supplies.length; i++) {%>
            <li><%= @supplies[i] %></li>
        <% } %>
        </ul>
        <p style="text-indent:2em;"><%=@address %></p>
        </textarea>
       
        <script>
       
(function () {

    var metaObject = {
        '\b': '\\b',
        '\t': '\\t',
        '\n': '\\n',
        '\f': '\\f',
        '\r': '\\r',
        '\\': '\\\\'
    };

    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, '\\"') + '"';
        }
    };
//selector ,必须,String, 模板容器textarea的ID值
//json,必须,对象字面量或JSON
//onsite,可选,Boolean,是否就地替换掉模板容器,默认true,如果为false,则返回一个文档碎片,交由用户自己插入到需要的地方
    dom.erb = function (selector, json, onsite) {
        onsite = !!onsite|| true;
        var el = document.getElementById(selector);
        if (!el) throw "找不到目标元素";
        var text = el.value,
            erb = dom.erb;
        if (!erb[selector]) {
            var arr = text.split(/\s*<%\s*|\s*%>\s*/g),
                buff = ["var __views = [];\n"]
                for (var i = 0, segment, n = arr.length; i < n; i++) {
                    segment = arr[i]
                    if (i & 1) { //偶数项,处理动态的逻辑
                        switch (segment.charAt(0)) {
                        case "#":
                            //处理注释
                            buff.push(erb.startOfHTML, dom.quote("<!--" + segment + "-->"), erb.endOfHTML);
                            break;
                        case "=":
                            if (segment.indexOf("@") !== -1) { //处理后台返回的变量(输出到页面的)
                                buff.push(erb.startOfHTML, segment.slice(1).replace(erb.rAt, "$1json."), erb.endOfHTML);
                            } else {
                                buff.push(erb.startOfHTML, segment.slice(1), erb.endOfHTML)
                            }
                            break;
                        default:
                            if (segment.indexOf("@") !== -1) { //处理后台返回的变量
                                buff.push(segment.replace(erb.rAt,  "$1json."), "\n");
                            } else {
                                buff.push(segment, "\n")
                            }
                            break;
                        }
                    } else { //奇数项,处理静态的HTML片断
                        buff.push(erb.startOfHTML, dom.quote(segment), erb.endOfHTML);
                    }
                }
                erb[selector] = new Function("json", buff.join("") + ';return __views.join("");')
        }
        var div = erb.parser;
        div.innerHTML = erb[selector](json);
        var fragment = document.createDocumentFragment();
        while (div.firstChild) {
            fragment.appendChild(div.firstChild)
        }
        return onsite ? el.parentNode.replaceChild(fragment, el) : fragment;

    }

    dom.erb.parser = document.createElement("div");
    dom.erb.startOfHTML = "\t__views.push(";
    dom.erb.endOfHTML = ");\n";
    dom.erb.rAt = /(^|[^\w\u00c0-\uFFFF_])(@)(?=\w)/g;


    window.dom = dom;
})();

            window.onload = function(){
                dom.erb("tmpl", {name:"司徒正美",
                supplies:["第一个LI元素","第二个LI元素","第三个LI元素","第四个LI元素"],
                address:"异次元"})
            }
        </script>
    </body>
</html>

PS:发现javascript模板没有想象中的糟糕,尤其是大流量的页面在无法使用UI库的情况下,这是个不错的选择,例子如qq zone与ニコニコ動画。