这篇文章发布于 2012年09月28日,星期五,00:34,归类于 JS实例。 阅读 260130 次, 今日 3 次 61 条评论
by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=2649
一、搜索引擎的吐槽
//zxx: 本段内容与正文无关,可以快速跳过。
写文章之前,我总要去网上搜索相关资料,避免内容重复,顺便学习。
同样的,在这个风和日丽,阳光明媚的周三上午,我兴致勃勃地打开百度,搜索:“JS 模板 数据”,然后……
我擦,怎么都是些非原创的,低质量的内容~~
谷歌之,立马长舒一口气:
这种感觉就像是在厕所憋气撒尿,完事后冲出厕所终于呼吸到了一口新鲜空气……
然而,这些文章的内容,大部分都是介绍JS模板引擎的,而且看上去都是很高级的样子,它们或长成这个样子:
或长成这个样子(Yaya Template模板引擎):
for(var i=0;i<list.length;i++){ {$ <li>这是第 {% i %} 列:{% list[i] %}</li> $} } var list = [“红桃”,”方块”,”梅花”,”黑桃”]; var html = YayaTemplate(templateText).render({list:list});
还有类似的,这个样子的(EasyTemplate前端模板 – 作者杜欢?):
<#list data as list>
<li>这里是第${list_index} 列:${list}</li>
</#list>
var list = [“红桃”,”方块”,”梅花”,”黑桃”];
var html = easyTemplate.render(templateText,list); //templateText指模板语言
还有其他N多jquery template、 ace template、lite template……
我勒个去,这些乱七八糟的标记字符语句什么的只会让我辈们产生两种反应:
1. 哎呀呀,好多字符标记,眼花缭乱,看得我头晕晕~~
2. 矮油,看上去很高级吧,但是,香奈儿这种高级货对于我们底层大众来说过于闪耀,会不小心亮瞎了金钛狗眼的~~
结果还自诩“易学易用”什么的~~果然,巴神的世界不是我等所能理解的!
好好的一个帅哥,如果改造的过于夸张,在不深入了解的情况下,会吓着人家小妹妹的。比方说你丫把自己变成了绿巨人,或是变成爬上摩天楼打飞机的巨猩猩~~
因此,所谓HTML模板,如果折腾地过于夸张,在这个卖萌的年代,会吓着那些做前端的新人的。
我这里也要介绍HTML模板,也是结合JSON数据的,但是很接地气,不是“引擎”,穿着简单质朴,长像不夸张;且灵活多变,能解决实际问题。
二、面向数据的编程
实际上,去年(2011)年初的时候,我就写过“js面向数据编程(DOP)一点分享”一文,里面就曾提到“HTML模板”的概念,如下对截图的截图:
不过,这里所说的“HTML模板”其实是“伪HTML模板”,怎讲?
- HTML结构代码完全嵌入在JS文件代码中(已经不是原汁原味的HTML code了),不利于后期修改维护等
- JS形式的模板,通过特定形式拼接字符串,需要一些额外的工作(不能直接ctrl+c, ctrl+v)
- 模板的数据应用不具有规律性,无法提炼出通用的模板处理方法
因此,我们就此忘记它……
假设你为了造福广大宅男,打算建一个可以将猪头肉批量转换成御姐和萌妹的工厂! →
你需要什么东西呢?
首先,转换的原料 – 猪头肉;其次,转换的模板 – 二次元的妹子原型们;最后,就是转换的方法 – 这是机密!
对应到本文,原料就是JSON数据,模板就是HTML模板,方法就是一个简单的正则匹配。
例如下面这个:
原料:
var JSON = { url: "ajax.php?author=www.zhangxinxu.com", data: [{ couponid: "111", imgsrc: "test1.JPG", resname: "俏江南 仙乐斯广场", traffic: "肇嘉浜路沿线", buynum: 180, cost: 100, discount: 8.5, price: 85 }, { couponid: "222222", imgsrc: "222222.jpg", resname: "申城五月天", traffic: "静安寺", buynum: 0, cost: 100, discount: 8.0, price: 80 }, { couponid: "3", imgsrc: "go-baby.jpg", resname: "申城五月天", traffic: "静安寺", buynum: 0, cost: 100, discount: 8.0, price: 80 }] };
模板:
<textarea style="display:none;"> <li> <a href="javascript:" data-id="$couponid$"> <img src="$imgsrc$" width="240" height="180" /> <p>$traffic$</p> <p>$buynum$人购买</p> <div> <div><del class="g6 db">¥$cost$现金券</del>$discount$折</div> <strong class="cr price r pr20">¥$price$</strong> </div> <h3>$resname$</h3> </a> </li> </textarea>
方法是固定的,一个基于字符串原型的扩展方法:
String.prototype.temp = function(obj) { return this.replace(/\$\w+\$/gi, function(matchs) { var returns = obj[matchs.replace(/\$/g, "")]; return (returns + "") == "undefined"? "": returns; }); };
然后,我们就可以根据实际具体JSON格式得到我们需要的HTML片段了,例如这里要获得完整的li标签列表HTML,一个JS数组循环就搞定了!
var htmlList = '' // textarea中的模板HTML , htmlTemp = $("textarea").value; JSON.data.forEach(function(object) { htmlList += htmlTemp.temp(object); }); // htmlList就是我们需要的HTML代码啦!
最后一行,$("ul").innerHTML = htmlList;
就会显示类似下面的效果啦!
关于HTML模板
一般而言,HTML模板都是放在<textarea>
标签中的,据说这样只会有一次的DOM渲染;且HTML的换行什么的可以完整保留。<textarea>
标签有个克星——就是其自身,<textarea>
标签无法嵌套<textarea>
标签;因此,含有文本域的HTML片段不能直接放在<textarea>
元素中作为模板。
上面的快速示例就是使用的<textarea>
标签作为HTML模板的容器。其中,您会看到N多$$
符号夹住的字符片段,这些就是HTML模板中的动态变量:
这些名字是与JSON数据中每个数据对象的关键字对应的(不区分大小写):
JSON对象中的关键字可以多余(不被使用,忽略)或缺失(空字符串匹配),因此,可以很随意定制。
HTML模板的动态变量以及JSON数据的关键字(上图高亮的关键字)都是后台那边(php/.net/Java)控制的,这样,维护起来就相当的轻松。后台只需要关心数据,前端这边只需要关心呈现以及交互;后期修改,如添加关键字,或列表样式变动,无需改动JavaScript文件;只要样式改动不是很复杂,前端工程师这边指头都不需要动一下,直接后台工程师加加减减$key$
就可以了!至少我公司的服务器端程序员们很喜欢这个~~
这里,使用两个$
作为特殊关键字标示,纯属个人爱好,因为我喜欢我的眼睛像下面这样:
您可以自己找些稀奇的字符作为特殊标示,不过,对应的,扩展的temp
方法中的正则表达式也要做相应修改。
关于JSON数据
所谓“引擎”,看似功能强大,但是,可定制性较差~~我这里的JSON数据您几乎可以随意定制,或数组,或对象;可以根据不同的页面具体的需求做相应的数据设计,只要保证temp
处理的时候的参数是纯生的Object
就可以了!
关于扩展方法temp
就是上面的
String.prototype.temp = function() { /* ... */ };
方法。
不过自己感觉应该有更简单高效的正则匹配替换,望高人指点!!!
在实际应用的时候,只要在JavaScript代码中放入这几行代码,我们就可以很简单从容地使用我们的HTML模板了!
三、适用模板数据呈现的技术场景
我们不能为了技术而技术,因此,HTML模板呈现技术不是撒泡尿就该使用的。
我个人举得以下场景适合使用:列表并含有大数据量,多DOM的交互。
原因在于:我们前端这边,无论是HTML呈现,或呈现后的DOM交互,或数据处理都是针对的同一个JSON数据源。很显然,这是相当有益的做法:一方面可以大大提高性能 – 数据层的处理显然要比DOM上的处理高效N倍;二是大大降低的开发成本和后期维护 – DOM相互关联的复杂交互会死人的(一条数据可能多个DOM使用),但是,数据是唯一的,不存在相关关联的情况!
我最近折腾了一个ipad页面,关于现金券的:左右交互是相互关联的,左右的列表样式又不一样,左右均有滚动无限加载(需同时),但是,显示的数据字段都是一致的(虽有不同,但前面说过,数据源可多可少可定制,因此无碍),因此,这个页面显然使用HTML模板技术非常划算……因为……(我也不知道~~)
平时,那些基本上属于纯展示的列表,偶们就直接HTML repeat出来吧!
四、实例演示
眼见为实耳听为虚,嘴巴就算说出老茧,人家也不一定信了你的邪啊~~
您可以狠狠地点击这里:HTML模板与JSON下的JS交互demo
下图为源代码中部分HTML模板代码的截图:
实际上,上DEMO是HTML模板与面向数据编程结合的demo页面;数据来自互联网。
就不多说了,源代码直接右键右面查看就可以了~~
五、最后的结语
总结出来,本文内容很简单的:
一个HTML片段;一些JSON数据;一个对应的字符串匹配替换扩展方法;然后一个实际的JavaScript循环;最后,直接over!
从头到尾出现的稀奇的符号也就是一个大家并不觉得稀奇,反而有些喜欢的美元符号$
, HTML代码就是我们平常所见的HTML代码,JavaScript代码也是我们平常所见的JavaScript代码。很质朴,很简单,但是,关键时候能很好简化我们的开发。
而且,所有内容,包括规则,您都可以根据您自己的癖好进行定制哦,像大叔型的,正太型的都可以的哦~~
末了,感谢大家的阅读,希望本文的内容能够对您的学习有所帮助。行文仓促,见识有限,文章要是有表述不准确的地方,欢迎指正。
本文为原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=2649
(本篇完)
- HTML5 <template>标签元素简介 (0.524)
- js面向数据编程(DOP)一点分享 (0.376)
- ES6模板字符串在HTML模板渲染中的应用 (0.256)
- 翻译:ECMAScript 5.1简介 (0.107)
- JS前端创建html或json文件并浏览器导出下载 (0.107)
- 简单了解ES6/ES2015 Symbol() 方法 (0.107)
- 有意思:textarea resize属性下纯CSS交互效果 (0.101)
- HTMLUnknownElement与HTML5自定义元素的故事 (0.077)
- 盘点HTML字符串转DOM的各种方法及细节 (0.077)
- JS 标签模板(Tagged templates)什么时候使用? (0.077)
- div模拟textarea文本域轻松实现高度自适应 (RANDOM - 0.067)
您的博客是我火狐浏览器的开机默认页面,幸好现在没有这些乱七八糟的比喻,否则港真,身为前端妹子,会有一些不适。
感谢您不懈地分享知识!
写的什么玩意,看不懂
Fa♂Q
感觉张老师是变态.
说出了我的心声,我现在看也是尴尬癌都犯了,只怪当年太年轻。sign~
哥,你这样妹妹都昏了
htmlTemp = $(“textarea”).value; 拿到的值是undefined,用htmlTemp = $(“textarea”).html(); 可以拿到string。但是如果json中的数据中有 回车.. 就悲剧了…
Uncaught TypeError: Cannot read property ‘temp’ of undefined
我也是报这样的错,朋友你解决了吗
还没看完,我先来评个价。脑海中突然想起一首歌,来大家唱起来“妹妹你坐船头,哥哥我岸上走”
标题好嬴荡啊
这个demo和适合入门,单个的json字符串替换,如果json里面 是一个json对象 是不是需要自己扩展了?请问大神 有没有这方面可以推荐的小型框架?越简单越好 就是需要一个替换 和 循环 功能?
哥能具体沟通下吗??
HTML模板都是放在标签中的,据说这样只会有一次的DOM渲染;这句话怎么验证
张哥可以写的更详细一点吗
感觉好像是真的那么厉害,但是没看懂~
我也感觉很经典,但我感觉总不能理解博主的例子。。唉感叹
不知说甚
谢谢博主!但是只使用简单的json数据,不支持json对象嵌套。例如var data = {
title: ‘test’,
list: [{name: ‘Dem’, city: ‘北京’}]
};
文笔幽默风趣,既学到了知识,也还在看的时候基本不打瞌睡
楼主,在我看来你是一位有着丰富知识的前端前辈。但是我对你的文章真是不感冒。原因,太拖沓,太多废话。前辈,也许你是以这种诙谐的写风来带给读者们快乐的读书体验。但是不适每一个人在看关键代码的时候都都能接受笑话的。这篇文章我读了2分钟后才进入主题,要不是滑轮向下滚了很多,我早就退了。
楼主你讲的笑话真得不好笑,这一点你去问你老婆就可以证实。而且,我是想来学习东西的,你直接就告诉我什么是什么不好吗?写这些笑话,您写的累,我们看着也累。再加上你发的图,真的快看不下去了。还有你的那些比喻,比喻地非常不到位。希望楼主听了之后,不要打我,我说的是实话。
还要:楼主免费分享原创文章确实可赞,这一点值得我辈学习之。
正好用到这个,非常感谢
人家写博客想怎么写就怎么写,你不爱看就关掉,怎么那么多事?难道自己写个博客还得问下客官的喜好?
拜托这是个人博客,人家分享知识,爱怎么分享就怎么分享,无偿贡献好吗?有个故事是这样子的:有个土豪,每天都给门口不远处的一个乞丐10块钱,保持了一年;一年后突然就不给,于是那个乞丐就质问那个土豪:“为毛今天不给我10块钱”。
层主觉得不感冒,右上角直接x掉,写这么一大段,谁逼着你来看
狗粉!
画风实在太美!
比如:demo中的例子中每行可能会有一个或多个附件(数量不定),怎么办呢
我也有同样的疑惑,如果div里面嵌入了许多子div,那么我们还要做相应的判断
同问
@小米布枪
正则应该这样吧~
String.prototype.temp = function(obj){
return this.replace(/\$([^$]+)\$/g,obj[RegExp.$1]);
};
直接$1貌似不行,需要 RegExp.$1才阔以。
回复的时候犯了个大错误,内容中还写script标签会被过滤掉,结果还把完整的标签写上去,结果真的被过滤了
把模板放在标签中是不是会更好?type属性的值设为”text/plain” 不用担心本身不能套嵌自己本身的问题。基本上不太可能在套嵌的模板变量中会出现的本身,一般大内容写入数据库的时候,也会把标签给过滤掉
@剑霄 没错,确实是这样~
虽然没看到,但是我笑了`太jb幽默了~
不利于搜索吧。
@小米布枪
为什么小米的那个正则表达式我这就不行呢 obj[$1]不能获取啊
JSON.data.forEach(function(object) {
htmlList += htmlTemp.temp(object);
});
这个forEach函数是js原生的吗
求指教啊
@小马 部分浏览器是,IE9+以及其他现代浏览器。
用 JavaScript 模板后对搜索引擎就很不友好了, 这个也得考虑进去.
不知鑫爷有没有看过Handlebars,我把它用在手机客户端,效果还不错啊,简化了大量代码。
有很多前端知识都是从你的博客里学到的,不过跟以前的文章相比,现在无关的东西占了一半,看完一篇文章要花很长时间。
你的博客 相当不错 很多文章写的 精彩 但是有点瑕疵 我觉得 就技术 就谈论技术 别插那些个 东西 你懂的 这只是个人建议 如有冒犯 见谅
如果不是为了效果不建议用js输出数据,html和css本身就是基层数据,万般变化都应该由服务器端完成。
关于正则:
/\$\w+\$/gi应该改为 /\$.+\$?/g,
.+的意义:第一性能会好点,第二就算用\w依然不能完全避免冲突。
?的意义,如果人你的模板都变成了一行,那你的正则就该贪吃了。
String.prototype.temp = function(obj) {
return this.replace(/\$(.+)\$?/g, obj[“$1”]);
};
@小米布枪 恩那,学习了,这个正则很赞!!
小米步枪这个正则竟然给我匹配了包括这样的标签结尾符,请大家不要用小米步枪这个正则。
thanks!
看完之后,我感觉很像ftl模板呀。。
意思是说 根本没必要使用各种JS模板引擎?
@tmdphp 本文面向新手~~
楼主博文里有一篇是关于JS 复制内容到剪贴板功能的帖子,我下了DEMO过来,发现没有alert(复制成功),函数没有被回调。但楼主挂在网上在线的却有alert.这是怎么回事。
@_西汐 访问方式(http://),安全机制。
z这个不就是jquery的各种mvc框架的原型吗,看看ember.js.
另外想知道你对Twitter Bootstrap的看法和分析。
@red 原来是这样,学习了!Bootstrap嘛,曾瞟了一眼,发现不是我喜欢的类型,就没去追她!
博主的demo的左侧选项卡怎么点不开?
@myway 与主题关系不大,没做功能~~
小妹妹愿意为哥哥买红薯,买蚯蚓。
好啊!
这是鑫哥在公司勾搭前端妹子的全过程么?
@vgche 别乱说话,让夫人听到了我就麻烦了~~
×
{title}
String.prototype.render = function (obj) {
var s = this.toString(),
html = “”,
fn = function (obj) {
s = s.replace(/{if\s+(\w+)}([\s\S]+?){\/if}/g, function ($1, $2, $3) {
if (obj[$2]) {
return $3.replace(/{else}.+/, “”);
} else {
return $3.replace(/.+{else}|.+/, “”);
}
});
s = s.replace(/\{(\w+)\}/g, function ($1, $2) {
if (obj[$2]) {
return obj[$2];
} else {
return “”;
}
});
return s;
};
if ($.isArray(obj)) {
for (var i = 0, l = obj.length; i < l; i++) {
html += fn(obj[i]);
}
} else {
html = fn(obj);
}
return html;
}
这是我在项目中用的,支持if 也可以传数组,自己就循环了
喜欢你的博文~文字很幽默