通过Backbone View渲染jQuery对象

时间:2012-06-27 22:50:41

标签: javascript jquery backbone.js hogan.js

我是Backbone.js开发的新手,在尝试渲染子视图时遇到了一些障碍。

目前,我已经有几个视图来呈现自定义下拉按钮以及其他元素。我基于DocumentCloud's code

采用了这种方法

这是我到目前为止所拥有的:

app.ui.SelectMenu = Backbone.View.extend({

    className: 'btn-group group-item',

    options: {
        id: null,
        standalone: false
    },

    events: {
        "click .dropdown-menu a": "setLabel"
    },

    constructor: function (options) {
        Backbone.View.call(this, options);

        this.items = [];
        this.content = JST['common-select_button'];
        this.itemsContainer = $('.dropdown-menu', $(this.content.render()));

        // Add any items that we may have added to the object params
        if (options.items) {
            this.addItems(options.items);
        }
    },

    render: function () {
        this.$el.html(this.content.render({
            label: this.options.label,
            items: this.itemsContainer
        }));
        this._label = this.$('.menu-label');
        return this;
    },

    setLabel: function (label) {
        $(this._label).text(label || this.options.label);
    },

    addItems: function (items) {
        this.items = this.items.concat(items);
        var elements = _(items).map(_.bind(function (item) {
            var attrs = item.attrs || {};
            _.extend(attrs, { 'class': 'menu_item' + (attrs['class'] || '') });

            var el = this.make('li', attrs, item.title);
            return el;
        }, this));

        $(this.itemsContainer).append(elements);
    }
});

到目前为止,我已成功渲染了我的按钮以及相应的标签,但在调用.dropdown-menu函数时似乎无法填充addItems

我假设当render命中时,由于我传递的是jQuery对象而不是字符串,因此无法填充items变量,但每当我使用items: this.itemsContainer.html()时,只是粘贴引号括起来的html ...我可以简单地替换引号,但这对我来说就像是一个黑客。

非常感谢任何帮助。谢谢!

1 个答案:

答案 0 :(得分:2)

jQuery的append不接受数组:

  

<强> .append( content [, content] )

     

content :要在匹配元素集中的每个元素末尾插入的DOM元素,HTML字符串或jQuery对象。
  内容:要在匹配元素集中的每个元素的末尾插入的一个或多个其他DOM元素,元素数组,HTML字符串或jQuery对象。

如果要在一次调用中追加多个元素,则必须将它们作为单独的参数提供:

$(x).append(e1, e2, e3, ...);

因此您必须使用apply将数组转换为单独的参数:

var $i = $(this.itemsContainer);
$i.append.apply($i, elements);

虽然这种诡计并非必要,但您可以在创建时逐一添加它们:

addItems: function (items) {
    this.items = this.items.concat(items);
    _(items).each(function (item) {
        var attrs = item.attrs || {};
        _.extend(attrs, { 'class': 'menu_item' + (attrs['class'] || '') });

        this.itemsContainer.append(this.make('li', attrs, item.title));
    }, this);
}

另请注意,_.each可以使用context参数,因此您无需单独_.bind次呼叫。而且我很确定this.itemsContainer已经是一个jQuery对象,所以你不需要再次包装$()

您的render也可能出现问题:

render: function () {
    this.$el.html(this.content.render({
        label: this.options.label,
        items: this.itemsContainer
    }));
    this._label = this.$('.menu-label');
    return this;
}

我怀疑items: this.itemsContainer将结束字符串this.itemsContainer,你可能会有更好的运气:

this.$el.html(this.content.render({ label: this.options.label });
this.$el.find('some selector').append(this.itemsContainer);

其中'some selector'当然取决于HTML结构;你也必须为此调整模板。


您的Github链接已损坏,因此我不知道您正在调整哪些代码。我知道您对constructor的使用是非标准的。为什么不使用标准initialize

  

构造函数/初始化 new View([options])

     

[...]如果视图定义了initialize函数,则在首次创建视图时将调用它。

你应该这样做:

app.ui.SelectMenu = Backbone.View.extend({
    // No 'constructor' in here or anywhere...
    initialize: function (options) {
        this.items = [];
        this.content = JST['common-select_button'];
        this.itemsContainer = $('.dropdown-menu', $(this.content.render()));

        // Add any items that we may have added to the object params
        if (options.items) {
            this.addItems(options.items);
        }
    },
    //...
});