-
Notifications
You must be signed in to change notification settings - Fork 93
/
baidutemplate.html
364 lines (297 loc) · 13.7 KB
/
baidutemplate.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="keywords" content="baidu template" />
<meta name="description" content="javascript前端模板" />
<title>https://github.com/wangxiao/BaiduTemplate/blob/master/baiduTemplate.js</title>
<script type="text/javascript">
/**
* baiduTemplate简单好用的Javascript模板引擎 1.0.6 版本
* http://baidufe.github.com/BaiduTemplate
* 开源协议:BSD License
* 浏览器环境占用命名空间 baidu.template ,nodejs环境直接安装 npm install baidutemplate
* @param str{String} dom结点ID,或者模板string
* @param data{Object} 需要渲染的json对象,可以为空。当data为{}时,仍然返回html。
* @return 如果无data,直接返回编译后的函数;如果有data,返回html。
* @author wangxiao
* @email [email protected]
*/
;(function(window){
//取得浏览器环境的baidu命名空间,非浏览器环境符合commonjs规范exports出去
//修正在nodejs环境下,采用baidu.template变量名
var baidu = typeof module === 'undefined' ? (window.baidu = window.baidu || {}) : module.exports;
//模板函数(放置于baidu.template命名空间下)
baidu.template = function(str, data){
//检查是否有该id的元素存在,如果有元素则获取元素的innerHTML/value,否则认为字符串为模板
var fn = (function(){
//判断如果没有document,则为非浏览器环境
if(!window.document){
return bt._compile(str);
};
//HTML5规定ID可以由任何不包含空格字符的字符串组成
var element = document.getElementById(str);
if (element) {
//取到对应id的dom,缓存其编译后的HTML模板函数
if (bt.cache[str]) {
return bt.cache[str];
};
//textarea或input则取value,其它情况取innerHTML
var html = /^(textarea|input)$/i.test(element.nodeName) ? element.value : element.innerHTML;
return bt._compile(html);
}else{
//是模板字符串,则生成一个函数
//如果直接传入字符串作为模板,则可能变化过多,因此不考虑缓存
return bt._compile(str);
};
})();
//有数据则返回HTML字符串,没有数据则返回函数 支持data={}的情况
var result = bt._isObject(data) ? fn( data ) : fn;
fn = null;
return result;
};
//取得命名空间 baidu.template
var bt = baidu.template;
//标记当前版本
bt.versions = bt.versions || [];
bt.versions.push('1.0.6');
//缓存 将对应id模板生成的函数缓存下来。
bt.cache = {};
//自定义分隔符,可以含有正则中的字符,可以是HTML注释开头 <! !>
bt.LEFT_DELIMITER = bt.LEFT_DELIMITER||'<%';
bt.RIGHT_DELIMITER = bt.RIGHT_DELIMITER||'%>';
//自定义默认是否转义,默认为默认自动转义
bt.ESCAPE = true;
//HTML转义
bt._encodeHTML = function (source) {
return String(source)
.replace(/&/g,'&')
.replace(/</g,'<')
.replace(/>/g,'>')
.replace(/\\/g,'\')
.replace(/"/g,'"')
.replace(/'/g,''');
};
//转义影响正则的字符
bt._encodeReg = function (source) {
return String(source).replace(/([.*+?^=!:${}()|[\]/\\])/g,'\\$1');
};
//转义UI UI变量使用在HTML页面标签onclick等事件函数参数中
bt._encodeEventHTML = function (source) {
return String(source)
.replace(/&/g,'&')
.replace(/</g,'<')
.replace(/>/g,'>')
.replace(/"/g,'"')
.replace(/'/g,''')
.replace(/\\\\/g,'\\')
.replace(/\\\//g,'\/')
.replace(/\\n/g,'\n')
.replace(/\\r/g,'\r');
};
//将字符串拼接生成函数,即编译过程(compile)
bt._compile = function(str){
var funBody = "var _template_fun_array=[];\nvar fn=(function(__data__){\nvar _template_varName='';\nfor(name in __data__){\n_template_varName+=('var '+name+'=__data__[\"'+name+'\"];');\n};\neval(_template_varName);\n_template_fun_array.push('"+bt._analysisStr(str)+"');\n_template_varName=null;\n})(_template_object);\nfn = null;\nreturn _template_fun_array.join('');\n";
return new Function("_template_object",funBody);
};
//判断是否是Object类型
bt._isObject = function (source) {
return 'function' === typeof source || !!(source && 'object' === typeof source);
};
//解析模板字符串
bt._analysisStr = function(str){
//取得分隔符
var _left_ = bt.LEFT_DELIMITER;
var _right_ = bt.RIGHT_DELIMITER;
//对分隔符进行转义,支持正则中的元字符,可以是HTML注释 <! !>
var _left = bt._encodeReg(_left_);
var _right = bt._encodeReg(_right_);
str = String(str)
//去掉分隔符中js注释
.replace(new RegExp("("+_left+"[^"+_right+"]*)//.*\n","g"), "$1")
//去掉注释内容 <%* 这里可以任意的注释 *%>
//默认支持HTML注释,将HTML注释匹配掉的原因是用户有可能用 <! !>来做分割符
.replace(new RegExp("<!--.*?-->", "g"),"")
.replace(new RegExp(_left+"\\*.*?\\*"+_right, "g"),"")
//把所有换行去掉 \r回车符 \t制表符 \n换行符
.replace(new RegExp("[\\r\\t\\n]","g"), "")
//用来处理非分隔符内部的内容中含有 斜杠 \ 单引号 ‘ ,处理办法为HTML转义
.replace(new RegExp(_left+"(?:(?!"+_right+")[\\s\\S])*"+_right+"|((?:(?!"+_left+")[\\s\\S])+)","g"),function (item, $1) {
var str = '';
if($1){
//将 斜杠 单引 HTML转义
str = $1.replace(/\\/g,"\").replace(/'/g,''');
while(/<[^<]*?'[^<]*?>/g.test(str)){
//将标签内的单引号转义为\r 结合最后一步,替换为\'
str = str.replace(/(<[^<]*?)'([^<]*?>)/g,'$1\r$2')
};
}else{
str = item;
}
return str ;
});
str = str
//定义变量,如果没有分号,需要容错 <%var val='test'%>
.replace(new RegExp("("+_left+"[\\s]*?var[\\s]*?.*?[\\s]*?[^;])[\\s]*?"+_right,"g"),"$1;"+_right_)
//对变量后面的分号做容错(包括转义模式 如<%:h=value%>) <%=value;%> 排除掉函数的情况 <%fun1();%> 排除定义变量情况 <%var val='test';%>
.replace(new RegExp("("+_left+":?[hvu]?[\\s]*?=[\\s]*?[^;|"+_right+"]*?);[\\s]*?"+_right,"g"),"$1"+_right_)
//按照 <% 分割为一个个数组,再用 \t 和在一起,相当于将 <% 替换为 \t
//将模板按照<%分为一段一段的,再在每段的结尾加入 \t,即用 \t 将每个模板片段前面分隔开
.split(_left_).join("\t");
//支持用户配置默认是否自动转义
if(bt.ESCAPE){
str = str
//找到 \t=任意一个字符%> 替换为 ‘,任意字符,'
//即替换简单变量 \t=data%> 替换为 ',data,'
//默认HTML转义 也支持HTML转义写法<%:h=value%>
.replace(new RegExp("\\t=(.*?)"+_right,"g"),"',typeof($1) === 'undefined'?'':baidu.template._encodeHTML($1),'");
}else{
str = str
//默认不转义HTML转义
.replace(new RegExp("\\t=(.*?)"+_right,"g"),"',typeof($1) === 'undefined'?'':$1,'");
};
str = str
//支持HTML转义写法<%:h=value%>
.replace(new RegExp("\\t:h=(.*?)"+_right,"g"),"',typeof($1) === 'undefined'?'':baidu.template._encodeHTML($1),'")
//支持不转义写法 <%:=value%>和<%-value%>
.replace(new RegExp("\\t(?::=|-)(.*?)"+_right,"g"),"',typeof($1)==='undefined'?'':$1,'")
//支持url转义 <%:u=value%>
.replace(new RegExp("\\t:u=(.*?)"+_right,"g"),"',typeof($1)==='undefined'?'':encodeURIComponent($1),'")
//支持UI 变量使用在HTML页面标签onclick等事件函数参数中 <%:v=value%>
.replace(new RegExp("\\t:v=(.*?)"+_right,"g"),"',typeof($1)==='undefined'?'':baidu.template._encodeEventHTML($1),'")
//将字符串按照 \t 分成为数组,在用'); 将其合并,即替换掉结尾的 \t 为 ');
//在if,for等语句前面加上 '); ,形成 ');if ');for 的形式
.split("\t").join("');")
//将 %> 替换为_template_fun_array.push('
//即去掉结尾符,生成函数中的push方法
//如:if(list.length=5){%><h2>',list[4],'</h2>');}
//会被替换为 if(list.length=5){_template_fun_array.push('<h2>',list[4],'</h2>');}
.split(_right_).join("_template_fun_array.push('")
//将 \r 替换为 \
.split("\r").join("\\'");
return str;
};
})(window);
</script>
</head>
<body>
<h3>BaiduTemplate单元测试用例</h3>
<!-- 测试模板1开始 -->
<script id='t:_1234-abcd-1' type="text/template">
<br>
1、基本输出(自动HTML转义): <%=value1%>
<br>
<br>
2、容错写法: <%=value2;%>
<br>
<br>
3、不转义输出: <%:=value3%> 或 <%-value3%>
<br>
<br>
4、容错写法: <%:=value4;%>
<br>
<br>
5、URL转义输出: <%:u=value5%>
<br>
<br>
6、容错写法: <%:u=value6;%>
<br>
<br>
7、UI变量在页面标签事件中使用转义: <%:v=value7%>
<br>
<br>
8、容错写法:<%:v=value8;%>
<br>
<br>
9、HTML转义输出:<%:h=value9%>
<br>
<br>
10、容错写法:<%:h=value10;%>
<br>
<br>
11、变量未定义自动输出空:<%=value11%>
<br>
<br>
12、模板直接输出特殊字符:5个斜杠 ///// 5个单引 ‘’‘’‘ 5个双引 “”“”“
<br>
<br>
13、注释:
<!-- HTML注释支持 -->
<%* 模板自带注释 *%>
<% //js注释方式
%>
<br>
<br>
14、判断语句:
<%if(value14){%>
<input type="text" value="<%:v=value14%>"/>
<%}else{%>
无值
<%}%>
<br>
<br>
15、循环语句:
<br>
<ul>
<%for(var i=0;i<value17.length;i++){%>
<li><%=value17[i]%></li>
<%}%>
</ul>
<br>
<br>
16、a标签 <br>
单引问题:<a target='_blank' href='http://www.baidu.com ' onclick='alert("test");'>test</a><br>
双引问题:<a target="_blank" href="http://www.baidu.com" onclick="alert('test');">test</a><br>
17、定义变量:
<%var varTest1 = value1%>
varTest1: <%=varTest1;%>
<br>
18、定义变量容错:
<%var varTest2 = value2;%>
varTest2: <%=varTest2%>
<br>
</script>
<!-- 测试模板1结束 -->
<div id="results"></div>
<script type="text/javascript">
window.onload=function(){
//测试数据,对应每个用例
var data={
value1:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value2:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value3:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value4:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value5:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value6:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value7:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span><span style="color:red;">\\\'\"</span>',
value8:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span><span style="color:red;">\\\'\"</span>',
value9:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value10:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value14:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value15:'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>',
value16:['<span style="color:red;">这是value</span>',123,'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>'],
value17:['<span style="color:red;">这是value</span>',123,'<span style="color:red;">http://wangxiao.github.com/BaiduTemplate/</span>']
};
//使用
var bat=baidu.template;
//设置分隔符
//bat.LEFT_DELIMITER='<!';
//bat.RIGHT_DELIMITER='!>';
//设置默认是否转义
//bat.ESCAPE = false;
var timestart = new Date().getTime();
//输出函数
var fun=bat('t:_1234-abcd-1');
var timeend = new Date().getTime();
alert('最大话编译一次时间:'+(timeend-timestart)+'毫秒');
timestart = new Date().getTime();
//输出HTML
var html=bat('t:_1234-abcd-1',data);
timeend = new Date().getTime();
alert('运行时间:'+(timeend-timestart)+'毫秒');
//显示结果
document.getElementById('results').innerHTML=html;
}
</script>
</body>
</html>