主干视图继承



我知道有人会将其标记为重复,但我浏览了几乎所有与此主题相关的帖子,这不是我想要的。所以这是自上周以来困扰我的事情。

我的任务是创建视图的原子设计。将有一个核心基础视图,然后另一个视图将扩展它,依此类推。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();
})

不起作用,因为 Backbone 不是在 BaseView 上运行初始化,而是首先调用 started,而 this.template 和所有其他内容都是未定义的。

然后我尝试用constructor替换它,而不是在 BaseView 上初始化。但是我最终this.$el一个未定义的错误,因为Backbone.View.constructor还没有被调用,所以还没有this.$el_ensureElement创建

所以通过一些研究,我发现的唯一一件事是使用

Backbone.View.prototype.constructor.apply(this,[options]);

但这也会导致类似的问题,即在 Backbone.View 的末尾,调用 this.initialize.apply(this, [options]),然后转到子对象初始化。所以我被困住了,无法解决这个问题。

我也知道我可以从 childview 调用父级的初始化函数,但这不可取,因为有很多子视图相互扩展。这就是我传递父对象以将以后的对象附加到其子对象的原因。

我试图完成的是创建一个包装器扩展对象,我可以稍后为另一个对象扩展它,但同时它应该在原始基本视图上运行一些常见任务,附加其他原型方法,然后调用调用者初始化。

如此伪

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 
}

如果我理解正确,您想在实例化孩子时运行"父视图"初始化方法吗?如果这是正确的,请参阅这篇文章:https://stackoverflow.com/a/8596882/1819684

您缺少的是该帖子中引用的关于"超级"的主干文档中的注释。

根据您的评论,我认为这就是您正在寻找的。您必须在 backbone 中显式调用"super"方法(父类的方法),如我引用的帖子所示。您可以在调用父方法之前和之后在"初始化"中执行任何您想要/需要执行的操作。我还发现了这一点:在没有初始化方法的情况下定义子视图可能会有所帮助。

var BaseView = Backbone.View.extend({
el: '#container1',
initialize: function(){
console.log('base view init');
this.render();
},
render: function(){
this.$el.html("Hello World 1");
}
});
var ChildView = BaseView.extend({
el: '#container2',
initialize: function() {
console.log('before call to parent (BaseView) init');
BaseView.prototype.initialize.apply(this, arguments);
console.log('ChildView init');
},
render: function(){
this.$el.html("Hello World 2");
}
});
var GrandChildView = ChildView.extend({
el: '#container3',
initialize: function() {
console.log('before call to parent (ChildView) init');
ChildView.prototype.initialize.apply(this, arguments);
console.log('GrandChildView init');
},
render: function(){
this.$el.html("Hello World 3");
}
});
var appView = new BaseView();
var appView = new ChildView();
var appView = new GrandChildView();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script>
<div id="container1">Loading...</div>
<div id="container2">Loading...</div>
<div id="container3">Loading...</div>

最新更新