沙漠之鹰和战术匕首--两款前端极简模板引擎

一、前言

说起前端模板引擎,那可真是多如牛毛,只要是前端coder,怎么着你都听说或用过几款,社区里面的文章也有介绍,或者问问度娘,这里不再赘述。其中比较知名的有 artTemplatedoT、mustache等。

本文介绍两款极简模板引擎:一款原创format引擎,一款优化template引擎。每个模板引擎都只有区区三十行左右的代码。

二、模板原则

模板概念的提出,不管起源是什么,最根本的原则一定是要解决开发中的问题:显示逻辑和数据逻辑能够分离。而实际开发需求中,两者分离的需求也不尽相同。

三、实际问题

在实际开发中,我们很多时候就是以下几种模板格式化需求:

1、将一堆数据直接塞到模板字符串中,源数据很多的时候是对象,保不齐也需要是数组或者多参;

2、偶尔用一下模板中的循环逻辑、判断逻辑;

3、如果太复杂,就干脆load一段json然后配合一个函数来处理了,复杂度和可维护性往往是冲突的;

四、战术匕首

先看第一个需求:直接将数据塞入到字符串中。

如果撇开前端模板不谈,你会用什么方法?很显然,在 js 中处理字符串最为得心应手的莫过于正则表达式,一个简单的 replace 函数就可以完成查询和替换的工作:

1 var str = "<div>我是一个{name}</div>";
2 var data = {name:"测试用例"};
3 var ret = str.replace(/\{(\w+)\}/g, function(match, index) {
4     return data[index] || match;
5 });
6 console.log(ret)

上面这段代码足够简单,但是思路却是非常赞,使用js内置的正则引擎来高效处理字符串替换。而这个工作其实就是“模板引擎”的本职工作。

考虑数据源多样性、正则表达式预编译等需求,最终完善成以下本文要介绍的原创format引擎

(function($, undefined) {
    //测试浏览器是否支持正则表达式预编译
    var baseReg = /\{([\w\.]+)\}/g, numReg = /^\d+$/,
        //预编译核心的正则表达式,以提高正则匹配效率
        formatReg = baseReg.compile ? baseReg.compile(baseReg.source, "g") || baseReg : baseReg,
        //其他工具函数
        toString = Object.prototype.toString, slice = Array.prototype.slice;
    //对外接口
    $.format = function(string, source){
        if( source === undefined || source === null )return string;
        var isArray = true, type = toString.call(source),
            //检测数据源
            data = type === "[object Object]" ? (isArray = false, source) : type === "[object Array]" ? source : slice.call(arguments, 1),
            N = isArray ? data.length : 0;
        //执行替换
        return String(string).replace(formatReg, function(match, index) {
            var isNumber = numReg.test(index), n, fnPath, val;
            if( isNumber && isArray ){
                n = parseInt(index, 10);
                return n < N ? data[n] : match;
            }else{ //数据源为对象,则遍历逐级查找数据
                fnPath = index.split(".");
                val = data;
                for(var i=0; i<fnPath.length; i++)
                    val = val[fnPath[i]];
                return val === undefined ? match : val;
            }
        });
    };
})(window.jQuery || window.Zepto || window);

如果拿一个武器来比喻的话,我觉得战术匕首很适合:短小精悍,使用顺手。

这把刀是这样用的:

//模板内置到js中
var tmpl = [‘<div>‘,
    ‘这里是一个{name}‘,
    ‘这里是其他元素‘,
‘</div>‘].join("");
var ret = $.format(tmpl, data);

//从页面元素中获取模板
var tmpl = $("#tmpl")[0].innerHTML;
var ret = $.format(tmpl, data);

以上引擎能解决实际开发中多数的模板需求了,但是在有些时候,数据结构比较复杂,有循环、判断等逻辑在内,这个场景下,format就力不从心了。

五、沙漠之鹰

jQuery的作者John Resig的一个Micro-Templating非常合我胃口,不足三十行的代码,完成了上述含有逻辑处理的模板引擎,如果说format是一把前端开发中的战术匕首的话,这个无疑是一只沙漠之鹰。不过,这只沙漠之鹰用起来不太顺手:

1、只有从页面读取的模板才能缓存,而且必须是id元素;

2、为了节约前缀数据名,使用with这个令我觉得不爽的语法;

3、识别标识符不能更换,因为有些模板会输出到 jsp 页面(请谅解我们项目的特殊性),<%%>跟jsp的标志混淆;

于是,动手优化了大神的代码,经过实践完善后的代码如下(中间完善的过程不再一一叙述):

(function($) {
    var tmplCache={}, fnCache={}, guid=0, toString = Object.prototype.toString, compile = function( tmpl, sp ){
        //默认分隔符
        var f = sp || "%",
            //动态创建函数,并增加数据源引用(data/my)
            fn = new Function("var p=[],my=this,data=my,print=function(){p.push.apply(p,arguments);};p.push(‘" +
                // Convert the template into pure JavaScript
                tmpl
                .replace(/[\r\t\n]/g, " ")
                .split("<" + f).join("\t")
                .replace(new RegExp("((^|" + f + ">)[^\\t]*)‘", "g"), "$1\r")
                .replace(new RegExp("\\t=(.*?)" + f + ">", "g"), "‘,$1,‘")
                .split("\t").join("‘);")
                .split(f + ">").join("p.push(‘")
                .split("\r").join("\\‘") + "‘);return p.join(‘‘);");
        return fn;
    };
    //对外接口
    $.template = function(tmpl, data, sp) {
        sp = sp||"%";
        var fn = toString.call(tmpl) === "[object Function]" ? tmpl
                : !/\W/.test(tmpl) ? fnCache[tmpl+sp] = fnCache[tmpl+sp] || compile(document.getElementById(tmpl).innerHTML, sp)
                : (function(){
                    for(var id in tmplCache)if( tmplCache[id] === tmpl ) return fnCache[id];
                    return (tmplCache[++guid] = tmpl, fnCache[guid] = compile(tmpl, sp));
                })();
        return data ? fn.call(data) : fn;
    };
})(window.jQuery || window.Zepto || window);

优化后的代码仅仅保留了最为核心的正则处理部分,同时增加以下特性:

1、任意模板均自动编译和缓存;

2、模板可以从js输入,也可以从页面id元素中获取;

3、支持自定义分隔符;

4、支持数据源别名;

因为最终模板会编译成一个函数,所以,js能干的事儿,模板中都可以干,同时语法上跟 jsp 的标志相似,有过类似开发经验的同学几乎没有任何学习成本,是的,这个引擎也仅仅三十行左右。

经过优化改造的引擎,趁手了,强大了,用起来才有沙漠之鹰的感觉:

这把枪的用法如下:

//模板内置到js中
var templ = "this is a <%=my.type%> <%=data.name%> too.";
var ret = $.template(templ, {name:"demo", type:"easy"});

//从页面id元素中获取模板
var ret = $.template("tmpl", {name:"demo", type:"easy"});

更多用法,请移步这里

六、语法和性能

模板引擎几乎都会自造模板语法,但是就开发习惯而言,当你看到以下模板的时候,不知道作为前端开发人员,你会不会糊涂:

<ul>
    {{ for (var val, i = 0, l = it.list.length; i < l; i ++) { }}
        {{ val = it.list; }}
        <li>用户: {{=val[i].user}}/ 网站:{{=val[i].site}}</li>
    {{ } }}
</ul>

所以,在性能和语法习惯上,我个人非常倾向于后者。而性能问题,在日常开发中,不会变态到循环 10000 次,每次有 100 条数据的情况吧?

这个引擎在性能上不占太多优势(IE下除外),但是极为精简的代码,可以让你感觉不到他的存在,完全可以放入全站js中,随时供您调遣和使用。

当然,如果你的需求远不止上述两个方面,你可以尝试使用其他模板引擎,当然,还是建议优先考虑开发习惯,然后参考性能、体积等因素综合考虑,其中 doT 是除了语法习惯有点别扭之外,性能和体积综合最为优秀的一款引擎。而企鹅公司的artTemplate在支持模板调试,并可以在node环境下使用,功能还是很强大的。

我用artTemplate的性能测试用例跑了一下,本文从这里开始到末尾均是性能测试截图。为了防止名称跟其他模板冲突,测试用例中,沙漠之鹰的名字换成了 mcTemplate。有兴趣的同学,可以到这里自己试验

上图为 chrome下高频测试结果

上图为 chrome下低频测试结果

上图为 firefox下高频测试结果

上图为 firefox下低频测试结果

上图为 IE11 下高频测试结果

上图为 IE11 下低频测试结果

IE7 下无法执行高频测试,直接卡死。上图是IE7低频测试结果

IE6 下无法执行高频测试,直接卡死。上图是IE6低频测试结果

时间: 2024-12-31 04:37:16

沙漠之鹰和战术匕首--两款前端极简模板引擎的相关文章

【JavsScript】推荐五款流行的JavaScript模板引擎

摘要:Javascript模板引擎作为数据与界面分离工作中最重要一环,受到开发者广泛关注.本文通过开发实例解析五款流行模板引擎:Mustache.Underscore Templates.Embedded JS Templates.HandlebarsJS.Jade templating. 近日一位20岁的开发者Jack Franklin在<The top 5 JavaScript templating engines>一文中向开发者们推荐了5款流行的JavaScript模板引擎.下面为该文的

几款常用的PHP模板引擎

PHP 模板引擎 广泛应用于分离模板和布局. 使用PHP模板引擎,可以让网站的维和更新容易,创造一个更加良好的开发环境,让开发和设计工作更容易结合在一起. 它肯定也有一些不足之外,比如性能 (大多数PHP模板引擎在这方面都还是做的比较好的) 和需要学习新的语法 (偶尔会这样). 说到这里, 使用一个 模板引擎 并不一定就适合每一个项目. 一个网站如果只有少许的页面,那很可能就不需要它.而如果是开发门户站.电子商务网站或其它Web应用程序,那使用它就可以改善开发进程. 这里是 19 个PHP 模板

一款好看+极简到不行的HTML5音乐播放器-skPlayer

Demo: github skPlayer在线预览 预览: 单曲循环模式预览: 使用方法: 方式1:NPM npm install skplayer 方式2:引入文件 引入css文件: <link rel="stylesheet" href="./dist/skPlayer.min.css"> 写入播放器DOM: <div id="skPlayer"></div> 引入js文件: <script src=

给开发者10款最佳的 JavaScript 模板引擎

使用模板的想法是使生活更容易,而不必编写所有的代码,只需要更改代码的一部分就可以.像许多模板支持多种语言,JavaScript也支持使用模板引擎.它允许您创建一个代码库,您可以开始构建你需要的应用程序.这里有10个最有用的JavaScript开发者模板引擎.希望能给开发者和设计者提供一定的帮助. 1.Mustache.js Mustache 是 logic-less 模板语法,可以使用在 HTML,配置文件,源代码等等地方.它是使用哈希表或者对象提供的值来扩展模板标签. 2.CoffeeKup

前端学PHP之自定义模板引擎

什么是网站模板?准确地说,是指网站页面模板,即每个页面仅是一个板式,包括结构.样式和页面布局,是创建网页内容的样板,也可以理解为已有的网页框架.可以将模板中原有的内容替换成从服务器端数据库中动态内容,目的是可以保持页面风格一致 PHP是一种HTML内嵌式的在服务器端执行的脚本语言,所以大部分PHP开发出来的Web应用,初始的开发模板就是混合层的数据编程.虽然通过MVC设计模式可以把程序应用逻辑与网页呈现逻辑强制性分离,但也只是将应用程序的输入.处理和输出分开,网页呈现逻辑(视图)还会有HTML代

前端开发调试线上代码的两款工具

用过 Charles 和 Fiddler 这两款,记录如下. 一.Charles Charles 界面简单直观,易于上手,数据请求控制容易,修改也简单,抓取数据的开始暂停也方便.支持 win,mac,linux. 1. 安装前提Charles 需要有 Java 环境,请提前下载安装 JDK.JDK 已经 8 了. 根据自己的系统选择对应的JDK.我的是 win7,双击安装,一直下一步就哦了.在命令行窗口输入以下命令,出现截图所示就表示 JDK 安装成功了 2. 下载 Charles Charle

这50款前端热门工具简直不要太好用了!(1)

19年,又是新的一年,"前端届",又出了哪些新的"玩意",今天向你推荐目前比较热门新鲜度靠前的50款前端工具,希望在新的一年里,对你有所帮助. 一.构建工具 1. Parcel https://parceljs.org/ Parcel是一款极速零配置WEB应用打包工具,快速.几乎零配置是它最大的特点,开箱即用.相比webpack,Parcel对于新手来说未尝不是一个很好的选择. 2. Critters github.com/GoogleChrom- 一款webpac

Resty 一款极简的restful轻量级的web框架

https://github.com/Dreampie/Resty Resty 一款极简的restful轻量级的web框架 开发文档 如果你还不是很了解restful,或者认为restful只是一种规范不具有实际意义,推荐一篇osc两年前的文章:RESTful API 设计最佳实践 和 Infoq的一篇极其理论的文章 理解本真的REST架构风格 虽然有点老,介绍的也很简单,大家权当了解,restful的更多好处,还请google 拥有jfinal/activejdbc一样的activerecor

基于活动场景签到微会动平台上线发布两款酷炫微信现场扫码签到产品

移动互联网.智能手机.社交媒体的快速普及,使得以微信为主的移动终端成为展商和观众在互联网搜索引擎外,获取会议等市场活动信息的另一重要入口,也成为了近几年会议企业营销转战的必争之地.微信二维码也以几近简单粗暴的方式,挤满了从会议活动海报.会议活动入口各个角落,成为会议活动上无法忽视的常客. 微信现场互动产品现在已经是各类公司举办活动的首选,成为企业品牌粉丝沉淀.运营转.销售转化的必争之地,目前,市场上主流的与微信.微信公众号.微信小程序结合的活动场景现场互动应用项目有:扫码签到(能有效增加粉丝和用