现在我对Backbone有了一点了解(我希望)我已经通过这个应用程序用细齿梳理解它是如何工作的:
https://github.com/ccoenraets/nodecellar/tree/master/public
最让我难过的是windetails.js中的EL标签(这里:https://github.com/ccoenraets/nodecellar/blob/master/public/js/views/winedetails.js)
我会粘贴下面的相关代码,但我的问题是这个视图的EL属性是如何分配的?正如您在视图定义中所注意到的那样,没有定义EL标记,也没有分配idTag或className属性。但是我在firebug中验证了这个视图确实正在侦听DOM中间的DIV标记(实际上就在内容DIV的下面)。那它是如何附加在那里的呢?如果不是这样,Click处理程序将无法正常工作,但确实如此。以前以相同方式创建的所有先前视图都具有未附加的EL属性。
window.WineView = Backbone.View.extend({
initialize: function () {
this.render();
},
render: function () {
$(this.el).html(this.template(this.model.toJSON()));
return this;
},
events: {
"change" : "change",
"click .save" : "beforeSave",
"click .delete" : "deleteWine",
"drop #picture" : "dropHandler"
},
change: function (event) {
// Remove any existing alert message
utils.hideAlert();
// Apply the change to the model
var target = event.target;
var change = {};
change[target.name] = target.value;
this.model.set(change);
// Run validation rule (if any) on changed item
var check = this.model.validateItem(target.id);
if (check.isValid === false) {
utils.addValidationError(target.id, check.message);
} else {
utils.removeValidationError(target.id);
}
},
beforeSave: function () {
var self = this;
var check = this.model.validateAll();
if (check.isValid === false) {
utils.displayValidationErrors(check.messages);
return false;
}
this.saveWine();
return false;
},
saveWine: function () {
var self = this;
console.log('before save');
this.model.save(null, {
success: function (model) {
self.render();
app.navigate('wines/' + model.id, false);
utils.showAlert('Success!', 'Wine saved successfully', 'alert-success');
},
error: function () {
utils.showAlert('Error', 'An error occurred while trying to delete this item', 'alert-error');
}
});
},
deleteWine: function () {
this.model.destroy({
success: function () {
alert('Wine deleted successfully');
window.history.back();
}
});
return false;
},
dropHandler: function (event) {
event.stopPropagation();
event.preventDefault();
var e = event.originalEvent;
e.dataTransfer.dropEffect = 'copy';
this.pictureFile = e.dataTransfer.files[0];
// Read the image file from the local file system and display it in the img tag
var reader = new FileReader();
reader.onloadend = function () {
$('#picture').attr('src', reader.result);
};
reader.readAsDataURL(this.pictureFile);
}
});
修改 有很多关于这种模式的讨论: $(x)的.append(v.render()。EL)
有人纠正我,如果我错了,但据我所知,这是一个Jquery调用,在“x”标签处更新DOM,其中包含来自v对象的“el”属性的内容(在调用render之后) 。如果先前没有设置“el”属性,这种技术应该将内容呈现到DOM中,并且如果它具有先前从render方法写入的有效内容,则它是“未附加的div”。
然而,在将内容写入DOM后,“el”属性仍然是未附加的div,直到将其直接分配给DOM。
我通过Firebug验证了这个Backbone应用程序有两个视图,这两个视图以这种方式呈现,并且都具有未连接的div el属性。这些是wineList视图和homeView。但是,第3个视图是WineDetail视图,它似乎没有独立的EL属性。它的EL属性似乎是附加的,并且进一步促进了点击事件。我的问题是这个EL属性是如何附加并分配给DOM的?
答案 0 :(得分:1)
通过查看Backbone.View
的内部结构,可以找到答案。
查看构造函数:
var View = Backbone.View = function(options) {
this.cid = _.uniqueId('view');
this._configure(options || {});
//this function is responsible for the creation of the `this.el` property.
this._ensureElement();
this.initialize.apply(this, arguments);
this.delegateEvents();
};
确保View具有要呈现的DOM元素。如果this.el是 string,传递给$(),取第一个匹配的元素,然后 重新分配给el。否则,从id创建一个元素, className和tagName属性。 http://backbonejs.org/docs/backbone.html#section-133
既然我们知道this.el
的来源,请查看events docs,看看它是如何处理的。
视图在main.js
中实例化$('#content').html(new WineView({model: wine}).el);
修改强>
其中没有一个解释了如何设置View对象的EL属性 以及点击触发器的工作原理。
我会尝试更好地解释它:
this.el
是通过调用this._ensureElement
构造函数中的Backbone.View
创建的。我们还可以看到this.render
是从initialize
函数调用的,该函数在实例时运行。我们可以在this.render
中看到,我们将this.el
的内容设置为将this.template
应用于模型的结果。
现在,在Backbone.View
的初始化过程中,在调用this.initialize
之后,通过调用events
来处理this.delegateEvents
配置。这是事件侦听器将使用给定选择器附加的位置。 请注意,大多数事件都会直接附加到this.el
并使用事件委派,而不是直接将事件附加到子元素上。
此时,我们留下了this.el
,其中包含所有必需的标记,并设置了所有事件侦听器。但是,this.el
仍然不是DOM的一部分。
但是从代码中我们可以看到this.el
将在视图实例化后作为#content
元素的子元素附加到DOM:
$('#content').html(new WineView({model: wine}).el);
答案 1 :(得分:0)
这段代码中的最后三行:
events: {
"change" : "change",
"click .save" : "beforeSave",
"click .delete" : "deleteWine",
"drop #picture" : "dropHandler"
},
看起来像这个模式(查看事件结构中的第二行):
"click" = event to register a handler for
".save" = selector to use for selecting objects for the event handler
beforeSave = method to call when the event fires