1

我对 Backbone.js 开发相当陌生,在尝试渲染子视图时遇到了一些障碍。

目前,我有几个视图来呈现自定义下拉按钮以及其他元素。我已经根据DocumentCloud 的代码采用了这种方法

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

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 ......我可以简单地替换报价,但这对我来说就像是一种黑客行为。

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

4

1 回答 1

2

jQueryappend不接受数组:

.append( content [, content] )

content:要插入到匹配元素集中每个元素末尾的 DOM 元素、HTML 字符串或 jQuery 对象。
content:一个或多个附加 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将结束 stringifying 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);
        }
    },
    //...
});
于 2012-06-28T02:55:28.450 回答