【发布时间】:2017-10-04 10:34:08
【问题描述】:
我知道有人会将此标记为重复,但我浏览了几乎所有与此主题相关的帖子,这不是我想要的。所以这是自上周以来一直困扰我的事情。
我的任务是创建视图的原子设计。将有一个核心基础视图,然后另一个视图将扩展它,依此类推。 element->panel->window, element->panel->popup 等。使用 Backbone.View.extend 我可以简单地做到这一点
var BaseView = Backbone.View.extend({
initialize : function(options) {
this.$el.attr('cid', this.cid);
this.base = options.base || arguments[0]['base'];
this.parent = options.parent || arguments[0]['parent'];
this.children = [];
if(typeof this.template !== 'undefined') {
if (typeof this.template=='function') {
// do nothing. template is already a underscore template and will be parsed when first call;
}
else if (typeof this.template=='string' && this.template.substr(0,1)=='#') {
if ($(this.template).length >0 ) {
this.template = _.template($(this.template).html());
}
else {
console.warn('Template element ' + this.template + 'could not be located in DOM.');
}
}
else {
this.template = _.template(this.template);
}
}
else {
this.template = _.template('<span></span>');
}
if (typeof this.parent!=='undefined' && this.parent ) {
this.parent.add.apply(this.parent, [this]);
}
},
add: function(child){
this.children.push(child);
},
getChildren : function(){
return this.children;
},
clean: function(){
this.$el.empty();
},
close: function () {
BaseView.prototype.clear.apply(this, [true]);
this.undelegateEvents();
this.unbind();
this.stopListening();
this.remove();
},
clear: function(){
if (this.children.length > 0) {
empty = empty || false;
_.each(this.getChildren(), function (child, index) {
Baseview.prototype.close.apply(child);
});
this.children = [];
if (empty) {
this.$el.empty();
}
}
return this;
}
})
如果我尝试将其用作
var Layout = new BaseView.extend({
el: '#someElement',
template : '#sometemplate',
initialize : function(){
this.childView = new ChildView({parent: this, base: this, collection: someCollection});
return this;
},
render: function(){
this.clean().$el.append(this.template({}));
this.$('.content').append(this.childView.render().$el);
return this;
},
});
var ChildView = BaseView.extend({
tagName : 'div',
template : '#childTemplate',
initialize : function(){
return this;
},
render: function(){
var self = this;
this.clean().$el.append(this.template({}));
this.$list = this.$('ul');
_.each( this.collection.models, function(model){
var grandChildView = new GrandChildView({parent: self, base: self.base, model: model});
self.$list.append(grandChildView.render().$el);
})
return this;
}
});
var GrandChildView = BaseView.extend({
tagName : 'li',
template : '#grandChildTemplate',
initialize : function(){
return this;
},
render: function(){
this.clean().$el(this.template(this.model.toJSON()));
return this;
}
});
$(function(){
new Layout();
})
不起作用,因为不是在 BaseView 上运行初始化,而是 Backbone 调用首先启动,并且 this.template 和所有其他都未定义。
然后我尝试将其替换为constructor,而不是在 BaseView 上进行初始化。但后来我最终出现this.$el undefined 错误,因为尚未调用 Backbone.View.constructor 所以还没有 this.$el _ensureElement 创建的 _ensureElement
所以通过一些研究,我发现唯一的事情就是使用
Backbone.View.prototype.constructor.apply(this,[options]);
但这也会导致类似的问题,在 Backbone.View 结束时,调用 this.initialize.apply(this, [options]),然后改为初始化子对象。所以我被困住了,无法解决这个问题。
我也知道我可以从子视图中调用父级的初始化函数,但这并不可取,因为有很多子视图相互扩展。这就是我传递父对象以将后面的对象附加到它的子对象的原因。
我想要完成的是创建一个包装扩展对象,稍后我可以为另一个对象扩展它,但同时它应该在原始基础视图上运行一些常见任务,附加额外的原型方法,然后调用调用者初始化。
太假了
var BaseView {
extend Backbone view with the passed arguments,
check for base, parent arguments and set them
check for template option, if exists then get the element, create template function and replace with the string one,
if there is parent view passed, then attach yourself to children of parent
call your own initialize method,
return
}
【问题讨论】:
-
这是make a good base class with Backbone 的不同方式。看起来很多职责没有在正确的类中处理。我从来不需要将父类传递给它的子类,由父类处理子类并监听事件总是更好的,这样子类可以保持专注和可重用。
-
谢谢。是的,我同意你提到的亲子关系。但具有原子设计理念。子继承可能有额外的东西。想想像旧的 ExtJs 之类的东西。原始基类是 Ext.Element,它创建一个空的 div 元素、id 等属性。然后 Ext.Panel 扩展 Ext.Element,并使用 Ext.Elements 功能,添加面板标题、正文、设计等,然后 Ext.Window 使用几乎相同的功能但浮动等扩展 Ext.Panel。它们都有初始化方法并被调用为了到达主要元素。
-
但是在使用调用方配置初始化 Ext.Window 之前,首先创建 Ext.Element。我想要完成的是类似的。 BaseView 应该是一个处理大部分预初始化功能的包装器内容设置,然后在从中创建新对象时,它会将自身附加到父对象,因此当父对象被销毁时,所有子对象都可以使用它。否则,当父级被移除时,子级将成为孤儿。