Mustache和嵌套模板



我有一个类似树的设置,其中每个节点都包含自己的Mustache模板,该模板可能封装在父节点的模板中。

var templates = {
secondTmpl: Mustache.compile("<i>Yet another template.. Here's some text: {{text}}</i>     {{date}}"),
template: Mustache.compile("<b>{{val}}</b><p>{{{outlet}}}</p><ul>{{#list}}<li>{{.}}            </li>{{/list}}</ul> {{test}}")
};
var tree = [
{
template: "template",
data: { val: "yup!!", list: [1,2,3,4,5], test: function() { return new Date(); } },
children: [
{
view: "Main",
template: "secondTmpl",
data: { text: "Some Value", date: function() { return new Date(); } }
}
] 
}
];
function MainView(options) {
this.template = options.template;
this.data = options.data;
this.childViews = options.childViews;
this.el = document.createElement("div");
}
MainView.prototype.render = function() {
View.prototype.render.call(this);
this.postRender();
return this;
};
MainView.prototype.postRender = function() {
this.el.getElementsByTagName("i")[0].style.border = "1px dotted red";
};
function View(options) {
this.template = options.template;
this.data = options.data;
this.childViews = options.childViews;
this.el = document.createElement("div");
}
View.prototype.render = function(renderChildren) {
if(this.childViews) {
this.data.outlet = "<div class="outlet"></div>";
}
this.el.innerHTML = this.template(this.data);
if(this.childViews) {
this.childViews.forEach(function(view) {
this.el.getElementsByClassName("outlet")[0].appendChild(view.render().el);
}, this);
}
return this;
};
function traverse(node) {
var viewOptions = {
template: templates[node.template],
data: node.data
};
if(node.children) {
viewOptions.childViews = node.children.map(function(n) {
return traverse(n);
});
}
return node.view ? new window[node.view + "View"](viewOptions) : new View(viewOptions);
}
function init() {
tree.forEach(function(node) {
var view = traverse(node);
document.body.appendChild(view.render().el);
});
}
window.onload = init;​

此处的示例:http://jsfiddle.net/b4fTB/

我之所以将数据放在树中,是因为嵌套的模板因用户数据而异,而且许多模板可能封装在不同的模板中。

我不知道我在这里做的是不是很愚蠢,但它也允许我从C#中渲染模板,这很好。

所以,这个问题(当然欢迎对以上内容发表评论)。当处理带有嵌套模板的模板时,最好有一个简单的函数,只返回与实际模板相关的dom元素,而不返回嵌套模板中的dom元素。这可能吗?它是否可能以一种允许深度嵌套模板而不损失大量性能的方式实现?换句话说,我有两个模板,其中一个嵌套在jsfiddle中的另一个模板中。在处理dom时,最好不用担心父视图中的嵌套视图。

好吧,我想我自己也找到了办法。

以下代码需要splashjs和composejs:

var noop = function() {};
var templates = {
secondTmpl: Mustache.compile("<i>Yet another template..  {{{outlet}}}Here's some text: {{text}}</i> {{date}}"),
template: Mustache.compile("<b>{{val}}</b><p>{{{outlet}}}</p><ul>{{#list}}<li>{{.}}</li>{{/list}}</ul> {{test}}")
};
var tree = [
{
view: "Main",
template: "template",
data: { val: "yup!!", list: [1, 2, 3, "Four", 5], test: function() { return new Date(); } },
children: [
{
template: "secondTmpl",
data: { text: "Some Value", date: function() { return new Date(); } }
},
{
view: "Test",
template: "secondTmpl",
data: { text: "ANOTHER TEMPLATE", date: function() { return new Date(); } },
children: [
{
template: "template",
data: { val: "Pretty nested template", list: [56, 52, 233, "afsdf", 785], test: "no datetime here" }
}
]
}
] 
}
];
var View = Compose(function(options) {
Compose.call(this, options);
this.el = document.createElement(this.tag);
}, {
tag: "div",
render: function() {
if(this.childViews) {
this.data.outlet = "<div class="outlet"></div>";
}
this.el.innerHTML = this.template(this.data);
this.didRender();
if(this.childViews) {
var lastEl;
this.childViews.forEach(function(view) {
if(!lastEl) {
var outlet = this.el.getElementsByClassName("outlet")[0];
lastEl = view.render().el;
outlet.parentNode.replaceChild(lastEl, outlet);
} else {
var el = view.render().el;
lastEl.parentNode.insertBefore(el, lastEl.nextSibling);
lastEl = el;
}
}, this);
}
this.didRenderDescendants();
return this;
},
didRender: noop,
didRenderDescendants: noop
});
var TestView = View.extend({
didRender: function() {
var nodes = this.el.querySelectorAll("*");
for(var i = 0; i < nodes.length;i++)
nodes[i].style.border = "2px dotted red";
}
});
var MainView = View.extend({
didRender: function() {
var nodes = this.el.querySelectorAll("*");
for(var i = 0; i < nodes.length;i++)
nodes[i].style.backgroundColor = "lightgray";
}
});
function traverse(node) {
var viewOptions = {
template: templates[node.template],
data: node.data
};
if(node.children) {
viewOptions.childViews = node.children.map(function(n) {
return traverse(n);
});
}
return node.view ? new window[node.view + "View"](viewOptions) : new View(viewOptions);
}
function init() {
tree.forEach(function(node) {
var view = traverse(node);
window["view"] = view;
document.body.appendChild(view.render().el);
});
}
window.onload = init;

诀窍是将div.outlet替换为第一个子视图,而不是附加到它。然后,将其他子视图并排插入。

最新更新