2017-05-05 124 views
1

我知道有人将标志着这是重复的,但我经历了几乎所有与此相关的主题的帖子去了,这不是我期待的。所以这是自上周以来我的想法。骨干观的继承

我一直负责创建视图的原子设计。将会有一个核心基础视图,然后另一个视图将扩展它,等等。元素 - >面板 - >窗口,元素 - >面板 - >弹出等。随着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来取代它,而不是初始化的基本视角。但后来我结束了this.$el未定义的错误,因为Backbone.View.constructor没有被调用却又如此没有this.$el尚未正在由_ensureElement

因此创造了一些研究,我发现的唯一的事情是用

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

但是,这也导致类似的问题,在Backbone.View结束,对于this.initialize.apply调用(这一点,[选项]),然后进入到子对象初始化代替。所以我被卡住了,无法将这个包裹在我的头上。

我也知道,我可以从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 
} 
+0

这里有不同的方式[使得与骨干网的良好基础类(http://stackoverflow.com/a/40982556/1218980)。看起来很多责任不在正确的课堂上处理。我从不需要将父类传递给它的孩子,对于父母来说,处理孩子和倾听事件总是会更好,所以孩子班可以保持专注和可重用。 –

+0

谢谢。是的,我同意你提到的亲子关系。但在原子设计概念。孩子继承可能有其他的东西。想想像ExtJs这样的东西。原始基类是Ext.Element,它创建一个空的div元素,id等属性。然后Ext.Panel扩展了Ext.Element,并且使用了Ext.Elements功能,添加了面板头,主体,设计等,然后Ext.Window使用几乎相同的功能扩展了Ext.Panel,但它们都是浮动的,它们都有初始化方法并被调用以达到主要元素。 –

+0

但是在使用调用者的配置初始化Ext.Window之前,Ext.Element首先被创建。我试图完成的是类似的。 BaseView应该是一个处理大部分预初始化功能的包装器内容设置,然后在创建新对象时,它将自己附加到父对象上,所以当父对象被销毁时,所有的孩子都可以使用它。否则,当父母被移除时,孩子将成为孤儿。 –

回答

0

如果我理解正确的话,你要运行实例化一个孩子当“父视图的”初始化方法?如果这是正确的看到这篇文章:https://stackoverflow.com/a/8596882/1819684

你缺少的是在该帖子中引用的“超级”骨干文档中的说明。

基于您的评论,我认为这是你在找什么。你必须明确地在主干中调用“super”方法(父类的方法),如我引用的帖子所示。在你调用父方法之前和之后,你都可以在你的“初始化”中做任何你想要/需要做的事情。我也发现:Defining child views without an initialize method可能有帮助。

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>

+0

是和不是。我想首先调用父类的初始化方法,准备一些属性(模板等),然后继续孩子的初始化。因为也可以延长孩子。这样它就会覆盖它imo –

+0

我在你的评论中添加了一个你说的话的例子。我认为这是你想要的。 – gforce301

+0

感谢你的例子。我看到你做了什么。但正如我在我的问题中提到的,我不想,也不能在子构造函数中调用父类原型,因为它们可以位于不同的容器中,也可以从不同类型的类中扩展。这是我拥有父母和基本参数的主要原因,所以父母负责在被移除时处置孩子。否则,当我从一个容器中移除所有的孩子时,我将不得不手动处理垃圾回收,并且在开发团队中,它可能会被遗忘,并可能容易导致内存泄漏。 –