zoukankan      html  css  js  c++  java
  • 前端模板之acetemplate 循环列表(一)

    很早之前就接触过javascript的模板引擎,今天看了这篇文章后深受启发:初识前端模板 ,作者对目前流行的前端引擎作了深入的对比。基于性能和扩展性,兼容性的结果,我决定先对ace-temlate这个模板引擎进行一下演练。

    先看一下前面作者的分析比较图:

    image

    image

    先看下AceTemplate的源码:

    var AceTemplate = AceTemplate || {};
     
    (function(){
        /**
         * Ace Engine Template
         * 一套基于HTML和JS语法自由穿插的模板系统
         * http://code.google.com/p/ace-engine/wiki/AceTemplate
         * @author 王集鹄(wangjihu,http://weibo.com/zswang) 鲁亚然(luyaran,http://weibo.com/zinkey)
         * @version 2011-07-06 
          * @copyright (c) 2011, Baidu Inc, All rights reserved.
         */
     
        /* Debug Start */
        var logger = {
            /**
             * 打印日志
             * @param {Object} text 日志文本
             */
            log: function(text) {
                /*
                var dom = document.getElementById("log");
                if (dom) {
                    dom.value += text + "\n";
                }
                */
                window.console && console.log(text)
            }
        };
        /* Debug End */
        
        var htmlDecodeDict = { "quot": '"', "lt": "<", "gt": ">", "amp": "&", "nbsp": " " };
        var htmlEncodeDict = { '"': "quot", "<": "lt", ">": "gt", "&": "amp", " ": "nbsp" };
        var lib = {
            /**
             * 通过id获得DOM对象
             * @param {String} id
             */
            g: function(id){
                if (typeof id != "string") 
                    return id;
                return document.getElementById(id);
            },
            /**
             * HTML解码
             * @param {String} html
             */
            decodeHTML: function(html) {
                return String(html).replace(/&(quot|lt|gt|amp|nbsp);/ig, function(all, key) {
                    return htmlDecodeDict[key];
                }).replace(/&#u([a-f\d]{4});/ig, function(all, hex) {
                    return String.fromCharCode(parseInt("0x" + hex));
                }).replace(/&#(\d+);/ig, function(all, number) {
                    return String.fromCharCode(+number);
                });
            },
            
            /**
             * HTML编码
             * @param {String} html 
             */
            encodeHTML: function(html) {
                return String(html).replace(/["<>& ]/g, function(all) {
                    return "&" + htmlEncodeDict[all] + ";";
                });
            },
            /**
             * 获得元素文本
             * @param {Element} element
             */
            elementText: function(element) {
                if (!element || !element.tagName) return "";
                if (/^(input|textarea)$/i.test(element.tagName))
                    return element.value;
                return lib.decodeHTML(element.innerHTML);
            }
        };
        
        /**
         * 解析器缓存
         */
        var readerCaches = {};
        
        /**
         * 是否注册了所有模板
         */
        var registerAll = false;
     
        /**
         * 构造模板的处理函数
         * 不是JS块的规则
         *     非主流字符开头
         *         示例:汉字、#{value}、<div>
         *         正则:/^\s*[<>!#^&\u0000-\u0008\u007F-\uffff].*$/mg
         *     html标记结束,如:
         *         示例:>、src="1.gif" />
         *         正则:/^.*[<>]\s*$/mg
         *     没有“双引号、单引号、分号、逗号,大小括号”,不是else等单行语句、如:
         *         示例:hello world
         *         正则:/^(?!\s*(else|do|try|finally)\s*$)[^'":;,\[\]{}()\n\/]+$/mg
         *     属性表达式
         *         示例:a="12" b="45"、a='ab' b="cd"
         *         正则:/^(\s*(([\w-]+\s*=\s*"[^"]*")|([\w-]+\s*=\s*'[^']*')))+\s*$/mg
         *     样式表达式
         *         示例:div.focus{color: #fff;}、#btnAdd span{}
         *         正则:/^\s*([.#][\w-.]+(:\w+)?(\s*|,))*(?!(else|do|while|try|return)\b)[.#]?[\w-.*]+(:\w+)?\s*\{.*$/mg
         * @param {String} template 模板字符
         */
        function analyse(template) {
            var body = [], processItem = [];
            body.push("with(this){");
            body.push(template
                .replace(/[\r\n]+/g, "\n") // 去掉多余的换行,并且去掉IE中困扰人的\r
                .replace(/^\n+|\s+$/mg, "") // 去掉空行,首部空行,尾部空白
                .replace(/((^\s*[<>!#^&\u0000-\u0008\u007F-\uffff].*$|^.*[<>]\s*$|^(?!\s*(else|do|try|finally)\s*$)[^'":;,\[\]{}()\n\/]+$|^(\s*(([\w-]+\s*=\s*"[^"]*")|([\w-]+\s*=\s*'[^']*')))+\s*$|^\s*([.#][\w-.]+(:\w+)?(\s*|,))*(?!(else|do|while|try|return)\b)[.#]?[\w-.*]+(:\w+)?\s*\{.*$)\s?)+/mg, function(expression) { // 输出原文
                    expression = ['"', expression
                        .replace(/&none;/g, "") // 空字符
                        .replace(/["'\\]/g, "\\$&") // 处理转义符
                        .replace(/\n/g, "\\n") // 处理回车转义符
                        .replace(/(!?#)\{(.*?)\}/g, function (all, flag, template) { // 变量替换
                            template = template.replace(/\\n/g, "\n").replace(/\\([\\'"])/g, "$1"); // 还原转义
                            var identifier = /^[a-z$][\w+$]+$/i.test(template) &&
                                !(/^(true|false|NaN|null|this)$/.test(template)); // 单纯变量,加一个未定义保护
                            return ['",', 
                                identifier ? ['typeof ', template, '=="undefined"?"":'].join("") : "", 
                                (flag == "#" ? '_encode_' : ""), 
                                '(', template, '),"'].join("");
                        }), '"'].join("").replace(/^"",|,""$/g, "");
                    if (expression)    
                        return ['_output_.push(', expression, ');'].join("");
                    else return "";
                }));
            body.push("}");
            var result = new Function("_output_", "_encode_", "helper", body.join(""));
            /* Debug Start */
            logger.log(String(result));
            /* Debug End */
            return result;
        }
     
        /**
         * 格式化输出
         * @param {String|Element} id 模板ID或是模板本身(非标识符将识别为模板本身)
         * @param {Object} data 格式化的数据,默认为空字符串
         * @param {Object} helper 附加数据(默认为模板对象)
         */
        AceTemplate.format = function(id, data, helper) {
            if (!id) return "";
            var reader, element;
            if (typeof id == "object" && id.tagName) { // 如果是Dom对象
                element = id;
                id = element.getAttribute("id");
            }
            helper = helper || this; // 默认附加数据
            reader = readerCaches[id]; // 优先读取缓存
            if (!reader) { // 缓存中未出现
                if (!/[^\w-]/.test(id)) { // 合法的标识符按id读取
                    if (!element) {
                        element = lib.g(id);
                    }
                    reader = this.register(id, element);
                } else {
                    reader = analyse(id);
                }
            }
            var output = [];
            reader.call(data || "", output, lib.encodeHTML, helper);
            return output.join("");
        };
        
        /**
         * 注册模板,如果没有参数则是注册所有script标签模板
         * @param {String} id 模板ID
         * @param {Element|String} target 模板对象或者是模板字符串,如果没有则默认获取id对应的DOM对象
         */
        AceTemplate.register = function(id, target) {
            if (!arguments.length && !registerAll) { // 无参数并且没有注册过
                registerAll = true;
                var scripts = document.getElementsByTagName("script");
                for (var i = 0; i < scripts.length; i++) {
                    var script = scripts[i];
                    if (/^(text\/template)$/i.test(script.getAttribute("type"))) {
                        var id = script.getAttribute("id");
                        id && arguments.callee.call(this, id, script);
                    }
                }
            }
            if (!id) return;
            if (readerCaches[id]) { // 如果已经注册
                return readerCaches[id];
            }
            if (typeof target != "string") {
                if (typeof target == "undefined") {
                    target = lib.g(id);
                }
                target = lib.elementText(target);
            }
            return readerCaches[id] = analyse(target);
        };
        
        /**
         * 注销模板
         * @param {String} id 模板ID
         */
        AceTemplate.unregister = function(id) {
            delete readerCaches[id];
        };
    })();

    1.使用Jquery输出列表

    Html模板部分

     
    <script id="t1" type="text/template">
                for (var i = 0; i < this.length; i++) {
                    var item = this[i];
                    <li>
                        <b>第#{i + 1}名</b><a href="#{item.url}" target="blank">#{item.title}</a>
                        if (item.isnew) {
                            <span>new!</span>
                        }
                    </li>
                }
        </script>
        <div>
            <ul id="t1out">            
            </ul>
        </div>

    Js部分

    <script type="text/javascript">
            $(function () {
                var movieList = [
                        {
                            title: "建党伟业",
                            url: "#"
                        },
                        {
                            title: "变形金刚3",
                            url: "#",
                            isnew: true
                        },
                        {
                            title: "功夫熊猫2",
                            url: "#"
                        },
                        {
                            title: "加勒比海盗4",
                            url: "#"
                        },
                        {
                            title: "3d肉蒲团",
                            url: "#"
                        }
                    ];
                $("#t1out").html(AceTemplate.format("t1",movieList));
            });
     
        </script>

    熟悉MVC的朋友是不是一眼就看出来,对,这就是JS的MVC模板引擎。

    是不是很简单,我们来总结一下循环输出的语法规则:

    1.使用Javascript原始的循环嵌套HTML代码定义

    for (var i = 0; i < this.length; i++) {
    var item = this[i];
    <li>
    <b>第#{i + 1}名</b><a href="#{item.url}" target="blank">#{item.title}</a>
    if (item.isnew) {
    <span>new!</span>
    }
    </li>

    2.使用Jquery的语法规则嵌套HTML定义

    $.each(this, function(i, item) {
    <li>
    <b>第#{i + 1}名</b><a href="#{item.url}" target="blank">#{item.title}</a>
    if (item.isnew) {
    <span>new!</span>
    }
    </li>

    DEMO下载:下载地址 (猛击它就可以下载了)

  • 相关阅读:
    读书笔记-8《构建之法》
    结对编程收获
    结对编程——四则运算器(UI第十组)
    读书笔记-7《构建之法》
    读书笔记-6《构建之法》
    【现代软件工程】个人总结
    【现代软件工程】6月中旬团队项目心得
    【读书笔记】——《代码大全》(六)
    【现代软件工程】五月团队项目心得
    【读书笔记】——《代码大全》(五)
  • 原文地址:https://www.cnblogs.com/dekins/p/2418886.html
Copyright © 2011-2022 走看看