【问题标题】:Javascript templating solution that allows after-rendering use of injected objects?允许在渲染后使用注入对象的 Javascript 模板解决方案?
【发布时间】:2015-09-08 17:10:44
【问题描述】:

所以,我正在构建一个基于 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 对象,我可以添加到我的文档中?

提前致谢,

【问题讨论】:

  • 您使用的是 Backbone,那么为什么要使用 onClick 属性而不是通过视图的 events 处理点击事件?尝试将功能代码与您的显示模板混合通常会导致混乱的混乱。
  • 感谢您的意见!如果没有办法在模板中链接,这就是我要做的。但是,我需要将模板中的对象 ID 映射到我的主干代码中的 ID,在多个层上,所以看起来生成的代码会比模板中的直接链接更复杂。
  • 你可以像这样在数据属性中折腾ids:stackoverflow.com/a/7825773/479863

标签: javascript backbone.js handlebars.js underscore.js-templating client-side-templating


【解决方案1】:

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

一种方法是使用数据属性来存储模型ids。您的模板如下所示:

{{#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 会跟踪它的 VMs,以便 VC#remove 可以在其所有子 VMs 上调用 remove

【讨论】:

    【解决方案2】:

    我的回答只是一个提示,我试图接近这个问题。请参阅此答案以获得更好的解决方案: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>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-12
      • 2014-08-06
      相关资源
      最近更新 更多