Closed majinkai closed 10 years ago
这个功能正在实现中…… 如果使用预编译工具,文件片段管理已经实现。参见 artTemplate 预编译工具:tmodjs
我目前已经选定使用artTemplate,因为我们是在客户端使用,所以自己对其做了简单的改造,使用XMLHttpRequest读取模板文件,现在最迫切的需求是模板继承特性,例如: layout.tp
<div>I am in layout.tp</div>
<div><%block('child')%></div>
child.tp
<%extends('layout.tp')%>
<%child%>
//Output
<%end%>
PS:看到你们一直在维护,就放心了
artTemplate 定位是一个小巧高效的支持预编译的模板引擎,所以暂时不会支持模板的 extends,只支持最基础的 include 功能(可以定义传入的数据)。 另外,使用 XMLHttpRequest 引入模板是否过于复杂?采用同步模式加载文件?
没错,是同步模式加载文件,主要是我们的工程非常大(不是single page),考虑到模板文件重用,并且想让前后端完全分离,后端暴露api,前端只负责数据展现和简单处理,如果没有include特性,可能前端每个html都需要引入很多公共模板,比如导航,footer这些。 include其实也够用了,只不过会有很多重复声明include的代码。
artTemplate 不提供模板管理,新的版本计划通过给外部暴露接口来实现文件级加载:
提供template.loadTemplate(id)
方法来加载模板。引擎默认在浏览器中使用,内部使用document.getElementById(id)
方式获取页面内嵌的模板。
加载外部模板可以复写这个方法,如使用 nodejs 或者 ajax 加载。由于模板内部也提供了include
语句,这里路径是相对于当前模板目录的,可以复写template.helpers.$include
来完成相对路径转换。
前端模板引擎种类众多,技术也很成熟,但是在前端模板文件级组织这一块仍然有很大的发展空间,欢迎 markerking 一起探讨。
我几乎比较了所有模板引擎,主要考虑了以下几点:
最终选出了art,期间也考虑过juicer,但是好久没更新了,放弃之。
因需要支持碎片化模板管理,所以参考了ejs在浏览器端对文件的支持,稍做改造,在性能上肯定没有document.getElementById(id)
高,但是对我们内部系统来说足够了,而且art本身就做了cache,改造成加载文件也同样有cache效果,损失性能也就在使用XMLHttpRequest
同步读取文件这块,这部分性能损失可以忽略了。
改造部分代码: 增加配置项extension后缀和路径配置
template.extension = '.tp' //自定义模板文件扩展名
template.basePath = '/' //自定义模板文件路径
template.get加入对id的是否为文件的判断
// 获取模板缓存
template.get = function (id) {
// 验证id有效性
if (typeof id !== 'string' && id === '') return null;
var cache, hasExtension, source;
// by marker:
// 增加文件读取,判断是否匹配后缀
hasExtension = id.length > template.extension.length && id.substring(id.length - template.extension.length) === template.extension;
if (_cache.hasOwnProperty(id)) {
cache = _cache[id];
} else if(hasExtension) {
source = template.getFile(id);
} else if ('document' in global) {
var elem = document.getElementById(id);
if (elem) {
source = elem.value || elem.innerHTML;
}
}
if (source) {
cache = template.compile(id, source.replace(/^\s*|\s*$/g, ''));
}
return cache;
};
添加获取文件内容方法
template.getFile = function(id) {
// 内部常用chrome浏览器,因此将原生支持放在第一位
var factories = [function() { return new XMLHttpRequest(); },function() { return new ActiveXObject("Msxml2.XMLHTTP"); },function() { return new ActiveXObject("Microsoft.XMLHTTP"); }];
for(var i = 0; i < factories.length; i++) {
try {
var request = factories[i]();
if (request != null) {
// false:同步读取模板文件
request.open("GET", template.basePath + id, false);
try {
request.send(null);
} catch(e) {
return null;
}
if (request.status == 404 || request.status == 2 ||(request.status == 0 && request.responseText == '') ) {
return null;
}
return request.responseText
}
} catch(e) {
continue;
}
}
return null;
}
刚才新建了一个分支,2.1.0版本,主要提供了文件级模板加载功能,内置 NodeJS 实现版本。
https://github.com/aui/artTemplate/tree/2.1.0(Beta)
nodejs 版本(node-template-simple.js)实现方式:
var fs = require('fs');
var path = require('path');
var template = require('./template.js');
// 提供新的配置字段
template.path = __dirname;
template.extname = '.html';
template.encoding = 'utf-8';
// 重写加载模板源文件方法
template.loadTemplate = function (id) {
id = path.join(template.path, id + template.extname);
try {
return fs.readFileSync(id, template.encoding);
} catch (e) {
}
}
// 重写`include``的实现方法,转换模板为绝对路径
template.helpers.$include = function (id, data, from) {
from = path.dirname(from);
id = path.join(from, id);
return template.render(id, data);
}
module.exports = template;
支持在 nodejs 下直接传入路径,例如:
var template = require('../src/node-template-simple.js');
template.path = __dirname;// 设置模板目录,默认为引擎所在目录
var html = template.render('node-template/index', {
title: '嵌入子模板',
list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
});
console.log(html);
ajax 加载同样可以使用插件的方式接入,markerking 可以看看你这里是否可以使用我提供的接口实现你要的功能。
不管内部实现如何,我们要给开发者暴露的是如下简单的接口:
一、使用路径调用模板:
template.render('index/main', data);
二、模板语法支持 include 语句复用模板:
{{include '../public/header'}}
这种方式其实就和服务端模板一样,非常适合大型项目。
后端环境很容易实现文件加载(正如 nodejs),浏览器端却十分麻烦,为了绕开浏览器的限制我采用了较为通用的预编译技术来实现:进击!前端模板工程化
明白了,我去试试了,感谢第一时间为用户做这么详细的支持,我来自韩都衣舍
类似EJS的文件加载,希望能够以文件片段的方式管理 模板是否支持extends,而非include