接 第1章 http://blog.youkuaiyun.com/zhgangxuan/article/details/50610883
第2章 下载地址 https://github.com/zhgangxuan/GXTemplate/blob/master/_oldfiles/version1/template02.html
源代码
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>text node</title>
<script src="data.js"></script>
<style>
.templatedevelopmodetextnode {
color: firebrick;
text-decoration: underline;
}
</style>
</head>
<body>
<h1>{#myitem.name}</h1>
<p>
Address: {#myitem.address}
-
Zip: {#myitem.zipcode}
-
Phone: {#myitem.phone}
</p>
</body>
<script>
var re_template_textbinding = /{#([^}]+)}/g;
function ProcessEval($__exp__) {
return eval($__exp__);
}
function ProcessTextNode(node, str) {
var arr;
var pos = 0;
str.replace(re_template_textbinding, function (exp, g1, index, full) {
if (!arr) arr = [];
if (pos < index)
arr.push(str.substring(pos, index));
pos = index + exp.length;
var span = document.createElement("span");
span.className = "templatedevelopmodetextnode";
span.title = exp;
span.innerText = ProcessEval(g1);
arr.push(span);
});
if (!arr)
return;
if (pos < str.length)
arr.push(str.substring(pos));
var p = node.parentNode;
for (var i = 0; i < arr.length; i++) {
var childnode = arr[i];
if (typeof (childnode) == "string") {
childnode = document.createTextNode(childnode);
}
p.insertBefore(childnode, node);
}
p.removeChild(node);
}
function TemplateExecute(node) {
if (node.nodeType == 3) {
var str = node.nodeValue;
if (str.indexOf('{#') != -1)
ProcessTextNode(node, str);
return;
}
if (node.nodeType != 1)
return;
switch (node.nodeName) {
case "SCRIPT":
case "STYLE":
return;
}
var cns = node.childNodes;
for (var ni = cns.length; ni > 0; ni--)
TemplateExecute(cns.item(cns.length - ni));
}
TemplateExecute(document.body);
</script>
</html>
目标:
让文本绑定后能分片处理, 把{#脚本返回值}作为span插进DOM中
实现过程:
这个例子与第1章不同的地方主要是ProcessTextNode的处理方法.
第一章只是简单的作如下处理:
function ProcessTextNode(node, str) {
var newstr = str.replace(re_template_textbinding, function (exp, g1, index, full) {
return ProcessEval(g1);
});
if (newstr != str) node.nodeValue = newstr;
}
第2章则使用str.replace(re_template_textbinding)的方式, 纯粹收集正则表达式所能搜索到的所有片段.
str.replace(re_template_textbinding, function (exp, g1, index, full) {
if (!arr) arr = [];
if (pos < index)
arr.push(str.substring(pos, index));
pos = index + exp.length;
var span = document.createElement("span");
span.className = "templatedevelopmodetextnode";
span.title = exp;
span.innerText = ProcessEval(g1);
arr.push(span);
});
由于每个符合正则表达式的前后, 都有可能存在普通的文本, 所以使用了pos变量记录了普通文本的开始位置. 并且适当地substring加到arr中.
如果实在收集不到任何符合正则表达式的, 那么就忽略当前节点. 否则把最后的普通文本加入到arr中.
if (!arr)
return;
if (pos < str.length)
arr.push(str.substring(pos));
收集符合正则表达式是本章的重点了. 而后面逐一处理数组的每一项则是很普通 : 把字符串转换成textnode, 和span一起, 逐项放到node的前面. 最后把原来的node删除掉.
var p = node.parentNode;
for (var i = 0; i < arr.length; i++) {
var childnode = arr[i];
if (typeof (childnode) == "string") {
childnode = document.createTextNode(childnode);
}
p.insertBefore(childnode, node);
}
p.removeChild(node);
实际上整个GXTemplate的v1.0版都已经上传到github的了. 接下来我们的业余时间主要是谢谢例子, 写写教程.
对于不懂得使用github的朋友, 可以直接下载源代码 https://github.com/zhgangxuan/GXTemplate/archive/master.zip