3

Backbone JS 视图非常“有用”,因为它们总是为您创建一个 DOM 节点,带有可配置的标签、id 和类。这是非常好的和包容的,但我发现它造成了一个不幸的情况:视图创建的 DOM 节点是一个隐藏的模板。

这对我来说在我们当前的项目中变得很明显,我们在前端和后端之间共享 Mustache 模板。使用 Backbone,当你想要一个看起来像这样的 DOM 时:

<section class="note">
  <textarea>
  ...
  </textarea>

  <input type="button" class="save-button" value="Save">
  <input type="button" class="cancel-button" value="Cancel">
</section>

您最终会创建如下所示的模板:

<textarea>
{{& content}}
</textarea>

<input type="button" class="save-button" value="Save">
<input type="button" class="cancel-button" value="Cancel">

但是现在您的模板与 Backbone 视图上的秘密根节点模板相关联,需要在服务器端复制该模板。DRY 封装就这么多!

setElement()除了在渲染时使用渲染的模板外,我没有立即看到解决此问题的明显方法,但这会带来其他问题,例如必须在每个render().

你是如何解决这个问题的?

4

2 回答 2

3

这是一个有趣的问题。我以前从来没有解决过这个特殊问题,但我尝试了一些选项,我想我找到了一个我喜欢的选项。

首先,这是代码:

//A base view which assumes the root element of its
//template (string, DOM node or $) as its el.
var RootlessView = Backbone.View.extend({

    //override the view constructor
    constructor: function(options) {

        //template can be provided by constructor argument or
        //as a subclass prototype property
        var template = options.template || this.template;

        //create a detached DOM node out of the template HTML
        var $el = Backbone.$(template).clone()

        //set the view's template to the inner html of the element
        this.template = $el.html(); 

        //set the element to the template root node and empty it
        this.el = $el.empty()[0];

        //call the superclass constructor
        Backbone.View.prototype.constructor.apply(this, arguments);
    }
});

本质上,您定义了一个基本视图,该视图期望每个派生视图都有一个template属性,或者将 atemplate作为选项哈希中的参数。模板可以是字符串、DOM 节点或 jQuery/Zepto 包装的 DOM 节点。视图假定模板的根节点为其el,并将template属性重新定义为根节点的内容。

您可以将其用作普通视图:

var View = RootlessView.extend({
    template: templateHtml,
    render: function() {
        this.$el.html(Mustache.render(this.template, this.model));
        return this;
    }
}); 

el属性从一开始就可用,并且在重新渲染时不会分离和重新连接。正常Backbone.View行为的唯一例外是,如果您定义了idcssClasstagName属性或参数,它们将被忽略,因为模板提供了根元素。

这没有经过广泛测试,但似乎通过了最简单的测试用例。我能想到的唯一缺点是templatehtml 字符串存储在每个视图实例(而不是原型)上,并且浪费了宝贵的内存字节,但这也不难解决。

这是一个关于 JSFiddle 的工作演示

于 2013-01-23T01:09:21.963 回答
2

解决方案是将根节点本身(在本例中为您的部分标记)包含在共享基本模板(无子模板)中,然后在实例化时初始化视图的“el”属性:

var existingElement = $('section.note')[0];
new View({el: existingElement}) 

然后,您可以继续将表单模板照常附加到 el 属性。

于 2013-01-23T00:10:22.147 回答