最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Javascript简单实现模板引擎例子
时间:2015-05-11 编辑:简简单单 来源:一聚教程网
一、背景
有两个大项目是从RD那边迁移过来,因为项目初期FE无人力跟进,所以都是后端同学直接用Smarty完成的前端部分;所以考虑到迁移的成本和方案,索性升级一下当前的JS模板引擎。
二、大致方案
支持extends标签
支持block标签
1、标签语法
为了便于模板词法分析,在模板左定界符后加上@来标识,标签名替换为属性设置方式,如extends标签:
<%@ extends="layout/layout.html" %>
2、extends实现方案
将整个extends标签替换成其指定的父模板的内容
3、block实现方案
首先理解block的概念:在父模板layout.html中提前挖好的坑,子模板中对block的实现,就好比萝卜,最后渲染的时候,就是一个萝卜一个坑的填充。
这样一来事情就好办多了,可将block的定义编译成js function的调用,假设父模板中block的定义是:
<%@ block="block_header" %>
最终可将其编译成:
block_header();
4、block进阶:父模板支持默认内容
smarty中的block是支持默认内容的,比如:(为了将smarty和js模板引擎区分开,下面用<&和&>分别标识smarty的定界符)
<&block name="block_header" &>
...
<&/block&>
那么,我们可以对应的在js模板引擎中支持如下格式:
<% block="block_header" {%>
...
<%}%>
没错,用一个相对投机的{和}将block默认内容包围起来,编译时,将block_header编译成一个function即可,为了避免和子模板中的block实现(也是一个function)命名冲突,所以给父模板中的block name定义加上parent标识,如:
function block_header__parent_ (){
__html += '
__html += '\t...\n';
__html += '
}
这样,如果子模板中没有对该block的(function)实现,那么这里可以直接执行这个blockx__parent方法即可。最终的样子差不多是这样的:
block_header__parent_();
function block_header__parent_ (){
__html += '
__html += '\t...\n';
__html += '
}
5、block进阶:子模板有block实现,甚至设置prepend、append模式
如题,假设子模板中有对该block的实现,可以用function来解决,如:
<%function block_header(){%>
我是header
<%}%>
那么,按照smarty的理解,应该是要用子模板中的block来覆盖父模板的block的,所以父模板block的定义处可编译为:
block_header();
function block_header__parent_ (){
__html += '
__html += '\t...\n';
__html += '
}
而对于smarty中定义的prepend模式继承block,如:
<&block name="block_header" prepend &>
我是header
<&/block&>
我们可以这样来简单模拟:
<%function block_header(prepend){%>
我是header
<%}%>
对,通过给block_header添加prepend参数的方式来解决。对于这种形式,父母般block的定义处可编译为:
block_header();
block_header__parent_();
function block_header__parent_ (){
__html += '
__html += '\t...\n';
__html += '
}
同理,对于append模式,我们可以把它编译成:
block_header__parent_();
block_header();
function block_header__parent_ (){
__html += '
__html += '\t...\n';
__html += '
}
6、block进阶:多级继承(layout.html ← middle.html ← child.html)
逐级prepend或者append貌似不太好整,不过可以变换下思路,采用smarty中的block嵌套形式,比如:
<&block name="block_header" &>
我是header
<&block name="block_header_inner" &>
我是inner
<&/block&>
<&/block&>
所以,在middle.html中,可以先实现block_header,再在其内部继续挖坑定义block_header_inner,比如:
<%function block_header(){%>
我是header
<%@ block="block_header_inner" %>
<%}%>
这样,在子模板child.html中只需要实现middle.html中的block_header_inner即可:
<%function block_header_inner(){%>
我是子模板中的inner
<%}%>
7、如何保证子模板中不会出现父模板未定义的东西?
这个是必须得去保证的,可以这样简单处理:在extends标签被替换的地方,强制加上:
return __html;
三、实践一下
1、layout.html
<%@ block="block_header" %>
<%@ block="block_content" {%>
这里是父layout中的内容
<%}%>
2、child.html
<%@ extends="layout.html" %>
<%function block_content(prepend){%>
我是子模板中的内容
<%}%>
<%function block_footer(){%>
我是子模板中的footer
<%}%>
我是子模板中多余的内容
3、编译后的中间文件
/*--/Users/zhaoxianlie/SourceCode/biz/trunk/demo/views/child.html--*/
exports.html = function ($_ROOT) {
return function ($_DATA) {
var __html = '';
__html += '';
__html += '
'
'
__html += '
block_content();
block_content__parent_();
function block_content__parent_() {
__html += '
}
__html += '
return __html;
// 其实故事到这里就结束了。。。
__html += '';
function block_content(prepend) {
__html += '我是子模板中的内容';
}
__html += '';
function block_footer() {
__html += '我是子模板中多余的内容';
}
__html += ' haha';
return __html;
};
};
4、运行以后
我是子模板中的内容
这里是父layout中的内容
我是子模板中的footer
差不多也就这点儿东西,就这么个原理,之后的smarty项目就好迁移了。