gpt4 book ai didi

backbone.js - Backbone View : Change attributes, CRUD 的正确示例,没有僵尸 View

转载 作者:行者123 更新时间:2023-12-02 03:34:10 24 4
gpt4 key购买 nike

试图制作一个合理的 Backbone 教学模型,展示利用 backbone 特性的正确方法,包括祖 parent 、 parent 和 child View 、模型和集合......

我正在尝试更改模型上的 bool 属性,该属性可以跨多个父 View 实例化。我该如何调整列表器以实现此目的?
当前的问题是,当您单击任何非最后一个 subview 时,它会将那个 subview 移动到末尾并重新实例化它。

Plnkr
点击“添加代表”
点击“添加节拍”(您可以多次点击)
单击除最后一个之外的任何节拍 View 会实例化同一节拍的更多 View

child :

// our beat, which contains everything Backbone relating to the 'beat'
define("beat", ["jquery", "underscore", "backbone"], function($, _, Backbone) {
var beat = {};

//The model for our beat
beat.Model = Backbone.Model.extend({
defaults: {
selected: true
},
initialize: function(boolean){
if(boolean) {
this.selected = boolean;
}
}
});

//The collection of beats for our measure
beat.Collection = Backbone.Collection.extend({
model: beat.Model,
initialize: function(){
this.add([{selected: true}])
}
});

//A view for our representation
beat.View = Backbone.View.extend({
events: {
'click .beat' : 'toggleBeatModel'
},
initialize: function(options) {
if(options.model){
this.model=options.model;
this.container = options.container;
this.idAttr = options.idAttr;
}
this.model.on('change', this.render, this);
this.render();
},
render: function(){
// set the id on the empty div that currently exists
this.$el.attr('id', this.idAttr);
//This compiles the template
this.template = _.template($('#beat-template').html());
this.$el.html(this.template());
//This appends it to the DOM
$('#'+this.container).append(this.el);
return this;
},
toggleBeatModel: function() {
this.model.set('selected', !this.model.get('selected'));
this.trigger('beat:toggle');
}
});

return beat;
});

家长:

// our representation, which contains everything Backbone relating to the 'representation'
define("representation", ["jquery", "underscore", "backbone", "beat"], function($, _, Backbone, Beat) {
var representation = {};

//The model for our representation
representation.Model = Backbone.Model.extend({
initialize: function(options) {
this.idAttr = options.idAttr;
this.type = options.type;
this.beatsCollection = options.beatsCollection;
//Not sure why we have to directly access the numOfBeats by .attributes, but w/e
}
});

//The collection for our representations
representation.Collection = Backbone.Collection.extend({
model: representation.Model,
initialize: function(){
}
});

//A view for our representation
representation.View = Backbone.View.extend({
events: {
'click .remove-representation' : 'removeRepresentation',
'click .toggle-representation' : 'toggleRepType',
'click .add-beat' : 'addBeat',
'click .remove-beat' : 'removeBeat'
},
initialize: function(options) {
if(options.model){this.model=options.model;}
// Dont use change per http://stackoverflow.com/questions/24811524/listen-to-a-collection-add-change-as-a-model-attribute-of-a-view#24811700
this.listenTo(this.model.beatsCollection, 'add remove reset', this.render);
this.listenTo(this.model, 'change', this.render);
},
render: function(){
// this.$el is a shortcut provided by Backbone to get the jQuery selector HTML object of this.el
// so this.$el === $(this.el)
// set the id on the empty div that currently exists
this.$el.attr('id', this.idAttr);
//This compiles the template
this.template = _.template($('#representation-template').html());
this.$el.html(this.template());
//This appends it to the DOM
$('#measure-rep-container').append(this.el);
_.each(this.model.beatsCollection.models, function(beat, index){
var beatView = new Beat.View({container:'beat-container-'+this.model.idAttr, model:beat, idAttr:this.model.idAttr+'-'+index });
}, this);
return this;
},
removeRepresentation: function() {
console.log("Removing " + this.idAttr);
this.model.destroy();
this.remove();
},
//remove: function() {
// this.$el.remove();
//},
toggleRepType: function() {
console.log('Toggling ' + this.idAttr + ' type from ' + this.model.get('type'));
this.model.set('type', (this.model.get('type') == 'line' ? 'circle' : 'line'));
console.log('Toggled ' + this.idAttr + ' type to ' + this.model.get('type'));
this.trigger('rep:toggle');
},
addBeat: function() {
this.trigger('rep:addbeat');
},
removeBeat: function() {
this.trigger('rep:removebeat');
}
});

return representation;
});

这个答案应该适用于所有 View ,能够在不影响非相关 View 的情况下创建或删除 View ,更改属性并使相关 View 自动更新。同样,这是作为一个教学示例来展示如何在没有僵尸 View 的情况下正确设置主干应用程序...

最佳答案

问题

您看到创建了重复 View 的原因在于 Beat View 的 render() 函数:

render: function(){
// set the id on the empty div that currently exists
this.$el.attr('id', this.idAttr);
//This compiles the template
this.template = _.template($('#beat-template').html());
this.$el.html(this.template());
//This appends it to the DOM
$('#'+this.container).append(this.el);
return this;
}

这个函数在以下情况被调用:

  1. 当与 View 关联的模型发生变化时
  2. 节拍 View 首先被初始化

第一个电话是导致问题的电话。 initialize() 使用事件监听器来监视模型的更改,以便在必要时重新渲染它:

initialize: function(options) {
...
this.model.on('change', this.render, this); // case #1 above
this.render(); // case #2 above
...
},

通常情况下,这很好,除了 render() 包含将 View 推送到 DOM 中的代码。这意味着每次与 View 关联的模型更改状态时, View 不仅会重新呈现,还会在 DOM 中复制。

这似乎会导致事件监听器绑定(bind)不正确方面的一大堆问题。据我所知,只有一个节拍时不会引起这种现象的原因是表示本身也会重新渲染并删除旧的僵尸 View 。我不完全理解这种行为,但它肯定与表示观看它的方式有关 beatCollection

解决方案

修复非常简单:更改 View 将自身附加到 DOM 的位置。 render() 中的这一行:

$('#'+this.container).append(this.el);

应该移动到初始化,像这样:

initialize: function(options) {
if(options.model){
this.model=options.model;
this.container = options.container;
this.idAttr = options.idAttr;
}
this.model.on('change', this.render, this);
this.render();
$('#'+this.container).append(this.el); // add to the DOM after rendering/updating template
},

Plnkr demo with solution applied

关于backbone.js - Backbone View : Change attributes, CRUD 的正确示例,没有僵尸 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24816698/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com