0

因此,我正在构建一个基于 Backbone.js 的应用程序,使用模板来呈现一些对象。

它正在工作,但是现在我需要在运行时动态引用对象,而且我不确定我见过的模板解决方案(下划线、车把、...)是否可以“扁平化”javascript。

为了说明,我有一个对象列表,比如说任务。我有一个可以这样简化的模型:

{{#each tasks.models as |task|}}
<div>
{{task.name}}
</div>
{{/each}}

现在,我需要在渲染完成后动态使用“任务”对象。例如,做这样的事情:

<div>
{{task.name}} - <button onClick="task.setComplete()" />
</div>

当然这种方式是行不通的;也不做类似的事情{{task}}.setComplete(),因为 {{task}} 在渲染时被转换为字符串。

有没有办法做到这一点?

我在想我需要闭包来保留对象,获得它们的唯一方法是不要展平 html,否则一切都会转换为字符串。

任何的想法?也许有模板库允许直接生成 DOM 对象,我可以添加到我的文档中?

提前致谢,

4

2 回答 2

1

我的回答只是一个提示,我试图接近这个问题。请参阅此答案以获得更好的解决方案:https ://stackoverflow.com/a/32493586/1636522 。

您可以使用索引或任何其他信息来查找该项目。这是一个使用 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 StackOverflow.' };
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>

于 2015-09-08T17:58:54.340 回答
1

这个问题用标记,所以你应该使用Backbone 的普通视图事件处理系统而不是onclick处理程序。你提到的tasks.models这么想大概tasks是一个集合。

一种方法是使用数据属性来存储模型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 结构。

如果视图的每个模型部分更复杂,那么您可以为每个模型的集合和子视图创建一个视图。在这种情况下,您的每个模型模板将如下所示:

<div>
    {{name}} - <button type="button">Completed</button>
</div>

不再需要数据属性。您将拥有一个新的每个模型视图,如下所示:

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的 s,以便VC#remove可以调用remove它的所有子VMs。

于 2015-09-10T05:08:42.757 回答