前端模板引擎
作者:heero 来源:heero博客 发布时间:2010-07-27 12:33:00
说起模板引擎,很多人会认为这是后台的东西(如PHP的Smarty、Java的Velocity),跟前端没有关系。然而,随着前端的逻辑变得越来越复杂,引入模板技术已经是非常必要了。
模板引擎的主要功能就是把变化的数据融入到不变的模板中,并生成最终结果。目前,前端的主要数据格式无非是XML和JSON。
如果选择XML作为数据格式,XSLT就是最佳的模板语言。大三时做的一个社团网站就是采用了这样的模式。XML+XSLT的缺点非常明显:
兼容性问题。XML+XSLT在不同浏览器下的转换方式有所不同。
XML、XSLT的语法都是极其冗余的,数据量相对较大。
如果选择JSON作为数据格式,似乎没有原生的模板语言可用,只能生拼字符串。例如,把下面代码中的data转换成一个表格:
var data = [
{ id : 1, name : 'Google', url : "google.com" },
{ id : 2, name : '百度', url : "baidu.com" },
{ id : 3, name : '有道', url : "youdao.com" }
], html = [];
html.push('<table>');
for (var i = 0; i < data.length; i++) {
html.push('<tr>');
html.push('<td>', data[i].id, '</td>');
html.push('<td><a href="http://', data[i].url, '" target="_blank">', data[i].name, '</a></td>');
html.push('</tr>');
}
html.push('</table>');
document.write(html.join("\r\n"));
看到这么多单引号、双引号之后,我觉得很头晕。这明显是不可取的。恰巧,大三下学期实习的时候,在一位前辈的代码中看到一种正则表达式做的简单模板引擎:
function parseTemplate(data, tpl) {
return tpl.replace(/\{\$(\w+)\}/g, function($0, $1) {
return data[$1];
});
}
有了parseTemplate后,连接字符串的过程就可以简化为(粗体部分为模板):
html.push('<table>');
for (var i = 0; i < data.length; i++) {
html.push(
parseTemplate(data[i], '<tr><td>{$id}</td><td><a href="{$url}" target="_blank">{$name}</a></td></tr>')
);
}
html.push('</table>');
这样优化过后,代码清晰了一点。然而,这种模板引擎无法应付稍微复杂一点的逻辑。假设我要突出显示排在第一位的数据,parseTemplate就无能为力了。
模板引擎必须要支持for、if等简单逻辑,否则其应用范围就会非常小。然而,要支持这些逻辑,又必须要有一套完善的语法系统。后来,还是著名的Javascript大师John Resig给我们解决了这个问题。他写了一个非常简短的函数实现了支持Javascript语法的模板引擎(详见此处)。其原理是把模板语言“编译”为Javascript的原生语法。这个引擎的优点在于:
可以使用任何Javascript支持的语法。
Parse模板的过程在闭包内执行,不会产生全局变量。
对“编译”后的模板进行了缓存,下次可以跳过“编译”的过程直接使用。
我对这段代码进行了少量改造,添加到jRaiser中,也就是jRaiser.util.parseTpl。主要是把模板语言中的“<%”和“%>”改成了“<#”和“#>”,因为前者容易与后端模板产生冲突。利用这个模板引擎,上面的代码可以再简化为:
var template = '\
<table>\
<# for (var i = 0; i < data.length; i++) { #>\
<tr>\
<td><#=data[i].id#></td>\
<td><a href="<#=data[i].url#>" target="_blank"><#=data[i].name#></a></td>\
</tr>\
<# } #>\
\
</table>';
document.write( $.util.parseTpl(template, { data : data }) );
至此,显示的逻辑已经完全在模板里面,代码清晰明了。


猜你喜欢
- assert断言声明,遇到错误则立即返回在使用python语言开发深度学习模型时,经常会遇到模型运行结束时才会发现的崩溃状态,或者得到的结果
- 题目:有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?程序分析:可填在百位、十位、个位的数字都是1、2、3、
- python检查值是否已经存在于字典列表中a = [ {'main_color': 're
- 注意:列转行的方法可能是我独创的了,呵呵,因为在网上找不到哦,全部是我自己写的,用到了系统的SysColumns(一)行转列的方法先说说行转
- ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。E
- 一、前提1、MySQL版本信息:MySQL版本:8.0.27注意:其他版本(主要5.x版本未验证)2、表字段:定义列CREATE TABLE
- 这是一个用python写解压大量zip脚本的说明,本人新手一个,希望能对各位有所启发。首先要注意的,在运行自己的脚本之前一定先备份或者复制出
- hello,我是小小炽,这是我写的第一篇博客,写博客一直都想在写,但是苦于能力尚浅,在各位大牛面前那既然是关公面前耍大刀了,但是其实想来每一
- JavaScript是一门OOP,而有些人说,JavaScript是基于对象的。1) 如何创建对象:1. 使用constructor,例如:
- 1、弹出菜单也叫上下文菜单,建立菜单并向菜单添加各种功能。2、右键监听鼠标。如右键点击,则根据位置判断弹出。3、调用Menupop方法。4、
- 开始: ------------------------------------------------------------------
- 一、MySQL 逻辑架构概览MySQL 最重要、最与众不同的特性就是它的可插拔存储引擎架构(pluggable storage engine
- sae中安装有python环境,想让sae导入自己下载的django或者其他模块,可以在svn中新建一个文件目录,比如site-packag
- Hello World一个简单的hello world例子:#!/usr/bin/env perluse strict;use warnin
- 问题描述(以下讨论范围仅限Windows环境): D:\develop\ide\mysql\mysql5.5\bin> mysql -
- 目录安装pytest插件编写测试用例忽略 HTTPS 错误和设置自定义视口大小持久上下文playwright结合Pytest为您的 Web
- 本文实例讲述了python统计文本文件内单词数量的方法。分享给大家供大家参考。具体实现方法如下:# count lines, sentenc
- 用户习惯大家都经常在提,习惯源于何出?回答可以是软件的用户习惯源于其不断使用过程中的印象积累。如果是这个软件刚诞生的时候呢?于是就得参考同类
- 本文实例讲述了MySQL无法存储emoji表情解决方案。分享给大家供大家参考,具体如下:今天学习爬虫爬伯乐在线的文章,由于在文章中有emoj
- 于是就测试了下: var stringToDom=function(text) { var doc; if(window.ActiveXOb