前端模版原理&实现(一)
【简单介绍】
目前流行的react,angular,vue等MV*框架,都离不开模版。目前比较流程的前端模版引擎,除了这几个框架本身的模版以外,还有:
https://github.com/janl/mustache.js 基于JavaScript的Logic-less(无逻辑或轻逻辑)模板。
https://github.com/twitter/hogan.js 上面的优化版,twitter出品
https://github.com/wycats/handlebars.js 完全兼容mustcache的语法
https://github.com/paularmstrong/swig 拥有更强悍的模板继承与block 重写功能
最不推荐的是jade,有点华而不实,过度设计,导致页面工作量大,性能差。
虚拟DOM时代流行的jsx就是无逻辑模版,之所以流行无逻辑模版或者轻逻辑模版,其主要原因是改动成本比较少。
对于模版来说,最简单而言,就是将某个可变数据放到适当的地方(填空),其次,可以控制这个区域输出不输入(if指令),或让其某个区域循环输入多次(for指令),更甚至,实现模版互相嵌套(layout与block)。
实现if和for有两种方法:
1、单纯的区域,插入一个js语句,里面有if语句或for语句。
2、语法糖,比如说v-for,v-if。语法糖的用法比直接引用js语句简单,但是带来学习成本与拓展功能。
每个模版的if,for指令语法都不一样,并且你想循环做一些处理,比如过滤一些数据,或突然在某处中断,这又得引用一些新的语句。随着模版要求前后共用,就有了传输成本,直接写js语句在模版里肯定比不过魔法糖。因此基于种种原因,mustache风格的模板就成为主流。
现在语法有三种:
PHP/ASP/JSP风格:
<% if ( list.length ) { %>
<ol>
<% for ( n=0; n<list.length; ++n ) { %>
<li>
<%= list[n] %>
</li>
<% } %>
</ol>
<% } %>
mustcache风格,高级语法有限,通常难自定义拓展:
{{#if list.length}}
<ol>
{{#each list item}}
<li>
{{ item }}
</li>
{{/each}}
</ol>
{{/if}}
属性绑定风格:
<ol v-if="list.length">
<li v-for="item in list">
{{item}}
</li>
</ol>
前两者只能出现于script、textarea等容器内部。因此<分隔符与标签的<容器容易造成冲突,并且也不利于IDE的格式化处理。
属性绑定风格则是MVVM时期最流行的模版定义风格,某页面某个区域就是一个模版,不需要进行append等操作。
【简单模版】
有时候,我们不需要太强大的javascript模版引擎(比如handlebarsjs),我们只是需要简单的模版里绑定一些非常简单的字段,示例如下:
首先我们先来定义我们需要的模版,在id为template的script块里:
1 <!doctype>
2 <html>
3 <head>
4 <meta charset=utf-8>
5 <title>Simple Templating</title>
6 </head>
7 <body>
8
9 <div class="result"></div>
10
11 <script type="template" id="template">
12 <h2>
13 <a href="{{href}}">
14 {{title}}
15 </a>
16 </h2>
17 <img src="{{imgSrc}}" alt="{{title}}">
18 </script>
19
20 </body>
21 </html>
然后我们通过ajax拿到了数据格式如下:
var data =[
{
title: "Knockout应用开发指南",
href: "http://www.cnblogs.com/TomXu/archive/2011/11/21/2257154.html",
imgSrc: "http://images.cnblogs.com/cnblogs_com/TomXu/339203/o_knockout2.jpg"
},
{
title: "微软ASP.NET站点部署指南",
href: "http://www.cnblogs.com/TomXu/archive/2011/11/25/2263050.html",
imgSrc: "http://images.cnblogs.com/cnblogs_com/TomXu/339203/o_vs.jpg"
},
{
title: "HTML5学习笔记简明版",
href: "http://www.cnblogs.com/TomXu/archive/2011/12/06/2277499.html",
imgSrc: "http://images.cnblogs.com/cnblogs_com/TomXu/339203/o_LearningHtml5.png"
}
]
我们有两种方式来绑定数据
1、简单的hardcode的方式,不灵活,不可取
var template = document.querySelector('#template').innerHTML,
result = document.querySelector('.result'),
i = 0, len = data.length,
fragment = '';
for ( ; i < len; i++ ) {
fragment += template
.replace( /\{\{title\}\}/, data[i].title )
.replace( /\{\{href\}\}/, data[i].href )
.replace( /\{\{imgSrc\}\}/, data[i].imgSrc );
}
result.innerHTML = fragment;
2、比较灵活,通过正则表达式来替换所有花括号的值,而无需一个一个的替换,相对比较灵活,但是要注意模版标签可能在数据里不存在的情况:
var template = document.querySelector('#template').innerHTML,
result = document.querySelector('.result'),
attachTemplateToData;
// 将模板和数据作为参数,通过数据里所有的项将值替换到模板的标签上(注意不是遍历模板标签,因为标签可能不在数据里存在)。
attachTemplateToData = function(template, data) {
var i = 0,
len = data.length,
fragment = '';
// 遍历数据集合里的每一个项,做相应的替换
function replace(obj) {
var t, key, reg;
//遍历该数据项下所有的属性,将该属性作为key值来查找标签,然后替换
for (key in obj) {
reg = new RegExp('{{' + key + '}}', 'ig');
t = (t || template).replace(reg, obj[key]);
}
return t;
}
for (; i < len; i++) {
fragment += replace(data[i]);
}
return fragment;
};
result.innerHTML = attachTemplateToData(template, data);
参照原文:
https://segmentfault.com/a/1190000006990480
http://www.cnblogs.com/TomXu/archive/2011/12/15/2284752.html

浙公网安备 33010602011771号