Javascript 允许渲染后使用注入对象的模板解决方案?
Javascript templating solution that allows after-rendering use of injected objects?
所以,我正在构建一个基于 Backbone.js 的应用程序,使用模板渲染一些对象。
它正在工作,但是现在我需要在运行时动态引用对象,而且我不确定我所见过的模板解决方案(下划线、把手等)是否可行,"flatten" javascript.
为了说明,我有一个对象列表,比方说任务。
我有一个可以这样简化的模型:
{{#each tasks.models as |task|}}
<div>
{{task.name}}
</div>
{{/each}}
现在,我需要在渲染完成后动态使用 'task' 对象。例如,做这样的事情:
<div>
{{task.name}} - <button onClick="task.setComplete()" />
</div>
当然这种方式不行;也不会做类似 {{task}}.setComplete()
的事情,因为 {{task}} 在渲染时被转换为字符串。
有办法吗?
我在想我需要闭包来保留对象,获得它们的唯一方法是不展平 html,否则所有内容都会转换为字符串。
有什么想法吗?也许有允许直接生成 DOM 对象的模板库,我可以将其添加到我的文档中?
提前致谢,
我的回答只是一个提示,我尽量贴近问题。请参阅此答案以获得更好的解决方案:.
您可以使用索引或任何其他信息来查找项目。下面是一个使用 Handlebars 的例子,假设每个任务都可以通过一个 id 来识别:
var tasks = [];
var source = $('#source').html();
var template = Handlebars.compile(source);
tasks[0] = { id: 42, label: 'coffee', description: 'Have a cup of coffee.' };
tasks[1] = { id: 13, label: 'help', description: 'Connect to Whosebug.' };
tasks[2] = { id: 40, label: 'smile', description: 'Make μ smile.' };
$('#placeholder').html(template({ tasks: tasks }));
function onClick (id) {
var task, i = 0, l = tasks.length;
while (i < l && tasks[i].id !== id) i++;
if (i === l) {
// not found
}
else {
task = tasks[i];
alert(task.label + ': ' + task.description);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.2/handlebars.min.js"></script>
<script id="source" type="text/x-handlebars-template">
{{#each tasks}}
<button
type="button"
class="task"
style="margin-right:.5em"
onclick="onClick({{id}})"
>{{label}}</a>
{{/each}}
</script>
<div id="placeholder"></div>
此问题带有 backbone.js 标记,因此您应该使用 Backbone 的普通视图事件处理系统而不是 onclick
处理程序。你提到 tasks.models
所以大概 tasks
是一个集合。
一种方法是使用 data-attributes 来存储模型 id
。您的模板将如下所示:
{{#each tasks}}
<div>
{{name}} - <button data-id="{{id}}" type="button">Completed</button>
</div>
{{/each}}
然后您的视图将设置如下:
Backbone.View.extend({
events: {
'click button': 'completed'
},
render: function() {
var t = Handlebars.compile($('#whatever-the-template-is').html());
this.$el.append(t({
tasks: this.collection.toJSON()
}));
return this;
},
completed: function(ev) {
var id = $(ev.currentTarget).data('id');
var m = this.collection.get(id);
// Do whatever needs to be done to the model `m`...
}
});
演示: https://jsfiddle.net/ambiguous/z7go5ubj/
所有代码都保留在视图中(所有数据都已经存在),模板只处理演示。没有全局变量、很好的关注点分离和惯用的 Backbone 结构。
如果视图的 per-model 部分更复杂,那么您可以为集合使用一个视图,为每个模型使用子视图。在这种情况下,您的 per-model 模板将如下所示:
<div>
{{name}} - <button type="button">Completed</button>
</div>
不再需要 data-attribute。您将有一个新的 per-model 视图,如下所示:
var VM = Backbone.View.extend({
events: {
'click button': 'completed'
},
render: function() {
var t = Handlebars.compile($('#whatever-the-template-is').html());
this.$el.append(t(this.model.toJSON()));
return this;
},
completed: function() {
console.log('completed: ', this.model.toJSON());
}
});
循环将移动到集合视图:
var VC = Backbone.View.extend({
render: function() {
this.collection.each(function(m) {
var v = new VM({ model: m });
this.$el.append(v.render().el);
}, this);
return this;
}
});
演示: https://jsfiddle.net/ambiguous/5h5gwhep/
当然在现实生活中你的 VC
会跟踪它的 VM
以便 VC#remove
可以在它的所有 child 上调用 remove
VM
s.
所以,我正在构建一个基于 Backbone.js 的应用程序,使用模板渲染一些对象。
它正在工作,但是现在我需要在运行时动态引用对象,而且我不确定我所见过的模板解决方案(下划线、把手等)是否可行,"flatten" javascript.
为了说明,我有一个对象列表,比方说任务。 我有一个可以这样简化的模型:
{{#each tasks.models as |task|}}
<div>
{{task.name}}
</div>
{{/each}}
现在,我需要在渲染完成后动态使用 'task' 对象。例如,做这样的事情:
<div>
{{task.name}} - <button onClick="task.setComplete()" />
</div>
当然这种方式不行;也不会做类似 {{task}}.setComplete()
的事情,因为 {{task}} 在渲染时被转换为字符串。
有办法吗?
我在想我需要闭包来保留对象,获得它们的唯一方法是不展平 html,否则所有内容都会转换为字符串。
有什么想法吗?也许有允许直接生成 DOM 对象的模板库,我可以将其添加到我的文档中?
提前致谢,
我的回答只是一个提示,我尽量贴近问题。请参阅此答案以获得更好的解决方案:
您可以使用索引或任何其他信息来查找项目。下面是一个使用 Handlebars 的例子,假设每个任务都可以通过一个 id 来识别:
var tasks = [];
var source = $('#source').html();
var template = Handlebars.compile(source);
tasks[0] = { id: 42, label: 'coffee', description: 'Have a cup of coffee.' };
tasks[1] = { id: 13, label: 'help', description: 'Connect to Whosebug.' };
tasks[2] = { id: 40, label: 'smile', description: 'Make μ smile.' };
$('#placeholder').html(template({ tasks: tasks }));
function onClick (id) {
var task, i = 0, l = tasks.length;
while (i < l && tasks[i].id !== id) i++;
if (i === l) {
// not found
}
else {
task = tasks[i];
alert(task.label + ': ' + task.description);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.2/handlebars.min.js"></script>
<script id="source" type="text/x-handlebars-template">
{{#each tasks}}
<button
type="button"
class="task"
style="margin-right:.5em"
onclick="onClick({{id}})"
>{{label}}</a>
{{/each}}
</script>
<div id="placeholder"></div>
此问题带有 backbone.js 标记,因此您应该使用 Backbone 的普通视图事件处理系统而不是 onclick
处理程序。你提到 tasks.models
所以大概 tasks
是一个集合。
一种方法是使用 data-attributes 来存储模型 id
。您的模板将如下所示:
{{#each tasks}}
<div>
{{name}} - <button data-id="{{id}}" type="button">Completed</button>
</div>
{{/each}}
然后您的视图将设置如下:
Backbone.View.extend({
events: {
'click button': 'completed'
},
render: function() {
var t = Handlebars.compile($('#whatever-the-template-is').html());
this.$el.append(t({
tasks: this.collection.toJSON()
}));
return this;
},
completed: function(ev) {
var id = $(ev.currentTarget).data('id');
var m = this.collection.get(id);
// Do whatever needs to be done to the model `m`...
}
});
演示: https://jsfiddle.net/ambiguous/z7go5ubj/
所有代码都保留在视图中(所有数据都已经存在),模板只处理演示。没有全局变量、很好的关注点分离和惯用的 Backbone 结构。
如果视图的 per-model 部分更复杂,那么您可以为集合使用一个视图,为每个模型使用子视图。在这种情况下,您的 per-model 模板将如下所示:
<div>
{{name}} - <button type="button">Completed</button>
</div>
不再需要 data-attribute。您将有一个新的 per-model 视图,如下所示:
var VM = Backbone.View.extend({
events: {
'click button': 'completed'
},
render: function() {
var t = Handlebars.compile($('#whatever-the-template-is').html());
this.$el.append(t(this.model.toJSON()));
return this;
},
completed: function() {
console.log('completed: ', this.model.toJSON());
}
});
循环将移动到集合视图:
var VC = Backbone.View.extend({
render: function() {
this.collection.each(function(m) {
var v = new VM({ model: m });
this.$el.append(v.render().el);
}, this);
return this;
}
});
演示: https://jsfiddle.net/ambiguous/5h5gwhep/
当然在现实生活中你的 VC
会跟踪它的 VM
以便 VC#remove
可以在它的所有 child 上调用 remove
VM
s.