Backbone.View.setElement 工作意外



一个简单的演示:

    var PersonListView = Backbone.View.extend({
        initialize: function () {
            this.listenTo(this.collection, 'add', this.addOne);
            this.listenTo(this.collection, 'reset', this.addAll);
        },
        addOne: function (model) {
            var subView = new PersonItemView({model: model});
            $(this.el).append(subView.render().el);
        },
        addAll: function () {
            $(this.el).empty();
            this.collection.each(this.addOne, this);
        },
        render: function () {
            this.addAll();
            return this;
        }
    });
    var PersonItemView = Backbone.View.extend({
        template: _.template($('#tpl_person_item').html()),
        initialize: function () {
            this.listenTo(this.model, 'remove', this.remove);
            this.listenTo(this.model, 'change', this.render);
        },
        render: function () {
            console.info("render person:" + this.model.get("name"));
            var el = $(this.template(this.model.toJSON()));
            this.setElement(el);
            return this;
        }
    });
    var p = new Person({name: 'name1'});
    var ps = new PersonList();
    ps.add(p);
    new PersonListView({
        el: $("#list"),
        collection: ps
    }).render();
    setTimeout(function () {
        p.set("name", "new name")
    }, 5000);

如图所示,我通过以下方式将模型的change事件绑定到视图:

this.listenTo(this.model, 'change', this.render);

但是,尽管调用了 render 方法,但元素不会更新到页面。

似乎setElement并没有将其el添加到 dom 中。

如何解决这个问题?

我对 Backbone 有点生疏,我对此作为解决方案并不完全满意,但这有效:将PersonItemView类更改为如下所示:

var PersonItemView = Backbone.View.extend({
    template: _.template($('#tpl_person_item').html()),
    initialize: function () {
        this.el = null;
        this.listenTo(this.model, 'remove', this.remove);
        this.listenTo(this.model, 'change', this.render);
    },
    render: function () {
        console.info("render person:" + this.model.get("name"), this.el);
        if (this.el == null) {
            var el = $(this.template(this.model.toJSON()));
            this.setElement(el);
        }
        else {
            $(this.el).replaceWith($(this.template(this.model.toJSON())));
        }
        return this;
    }
});

也许更好的解决方案是让PersonListView.addOne创建一个空的<li>元素并将其传递给PersonItemView的构造函数,然后PersonItemView.render总是可以使用replaceWith

当您更改模型时,仅执行 PersonItemView 的渲染。该函数正在更改视图的 el,但不根据您的代码更新 DOM。

由于您仅在集合视图中更新 DOM,因此即使在单个模型中进行更改时,只需呈现完整的集合

 var PersonListView = Backbone.View.extend({
        initialize: function () {
            this.listenTo(this.collection, 'add', this.addOne);
            this.listenTo(this.collection, 'reset', this.addAll);
            this.listenTo(this.collection, 'change', this.addAll);
        },

捷轩

解决方案 2:setElement 覆盖了元素的 el,因此您正在更新不在 DOM 中的元素。 所以不要使用 setElement 而只是更新相同的 el。

 var PersonItemView = Backbone.View.extend({
        render: function () {
            console.info("render person:" + this.model.get("name"));
            this.$el.html(this.template(this.model.toJSON());
            return this;
        }
    });

如果你想使用 setElement,请确保你再次将 el 添加到 DOM 中。 这在你的代码中没有发生。

最新更新