扩展骨干视图并以干净的方式继承选项

Ves*_*oen 6 javascript backbone.js

这是我关于SO的第一个问题所以我希望我没有搞砸.我已经检查了有关此问题的其他主题,但它们并未涵盖我所拥有的案例.

我正在Backbone之上构建一个库来创建移动应用程序.我将所有组件定义为主干视图的主要原因是因为我想在滚动时进行内存优化(隐藏东西/从DOM中删除内容).

让我首先介绍一下最理想的防守

为其他组件定义一个基类,使用一些默认属性和一些方便的方法,我需要在每个组件上.

UI.Component = Backbone.View.extend({
    viewOptions: ['children'],

    children: [],

    add: function(child) {
        this.children.push(child);
    }
});
Run Code Online (Sandbox Code Playgroud)

使用一些默认属性定义组件

UI.Header = UI.Component.extend({
    viewOptions: ['titleBarChildren', 'secondaryBarChildren', 'title', 'backButtonTitle'],

    titleBarChildren: [],

    secondaryBarChildren: [],

    title: '',

    backButtonTitle: 'Back'
});
Run Code Online (Sandbox Code Playgroud)

制作要在我的应用程序中使用的默认标头

MyApp.Headers.Default = UI.Header.extend({
    backButtonTitle: 'Terug',

    titleBarChildren: [
        new UI.SegmentedController({
            children: [
                new UI.Button('Lame example')
            ]
        })
    ]
});
Run Code Online (Sandbox Code Playgroud)

使用我的导航栏

var homePageNavbar = new MyApp.Header.Default({
    title: 'Homepage'
});
Run Code Online (Sandbox Code Playgroud)

现在让我们跑吧

console.log(homePageNavbar);
Run Code Online (Sandbox Code Playgroud)

并想象我们得到这个输出

// My properties, all nicely inherited
viewOptions: Array[5] //['children', 'titleBarChildren', 'secondaryBarChildren', 'title', 'backButtonTitle']
children: Array[0],
titleBarChildren: Array[1],
secondaryBarChildren: Array[0],
title: "Homepage",
backButtonTitle: "Terug"

// Some stuff that backbone assigns
$el: jQuery.fn.jQuery.init[1]
cid: "view12"
el: HTMLDivElement
options: Object
__proto__: ctor
Run Code Online (Sandbox Code Playgroud)

这是我最终想要得到的结果,然而这需要一些超出我经验的魔法.

在旁注中,我尝试使用"options"属性来处理我的所有自定义内容,但问题是当我创建多个视图实例时,选项是"共享"/引用彼此.

所以现在我希望我能用"viewOptions"方法获得更多运气,然后重写_configure方法

这首先是在UI.Component或它的孩子中完成的.我不希望这个库的用户在其标题保护(MyApp.Headers.Default = UI.Header.extend)中添加一些"样板代码"来扩展选项或其他.

现在我不得不从所有"后代"中得到所有的特性.而且我完全不知道如何去做.我试过跟踪骨干幕后发生的事情,但我无法绕过它.

因此,非常感谢非常感谢完成此任务的提示/技巧,非常欢迎替代方式或不符合我的确切要求的方法.

编辑1

看起来我有一些"有点"的东西,这就是它的样子

我重写_configure方法,将选项添加到实例中,注意this.getDefaultOptions()作为_.extend中的第一个参数

UI.Component = Backbone.View.extend({
  _configure: function(options) {
    var viewOptions = this.viewOptions;
    options = _.extend(this.getDefaultOptions ? this.getDefaultOptions() : {}, this.options || {}, options || {});
    for (var i = 0, l = viewOptions.length; i < l; i++) {
      var attr = viewOptions[i];
      if (options[attr]) this[attr] = options[attr];
    }
    this.options = options;
  }
});
Run Code Online (Sandbox Code Playgroud)

我将这个新方法添加到我的所有组件中,并没有在我的基础对象(UI.Component)中放置"共享"属性,因为我不能让它发挥得很好.

UI.Header = UI.Component.extend({

  viewOptions: ['children', 'backButtonTitle', 'title'],

  getDefaultOptions: function() {
    return {
      children: []
    };
  },
});
Run Code Online (Sandbox Code Playgroud)

现在,我使用这样的东西来定义我的标题

MyApp.Headers.Default = UI.Header.extend({
  options: {
    backButtonTitle: 'Terug',
    titleBarChildren: [
      new UI.SegmentedController({
        children: [
          new UI.Button('Lame example')
        ]
      })
    ]
  }
});
Run Code Online (Sandbox Code Playgroud)

我将保持现在的状态,看看这个"解决方案"是否存在,并将报告回来.如果您认为自己有更好的答案,请不要犹豫发布=)

编辑

这是我最新的方法,使用jQuery的深层拷贝,它似乎工作正常

var UI = {};
var App = {
  Headers: {}
};

UI.Component = Backbone.View.extend({
  blockDefaults: {
    children: []
  },

  initialize: function(options) {
    var combinedDefaultsAndOptions = $.extend(true, {}, this.blockDefaults || {}, this.defaults || {}, this.options || {}, options || {});
    _.defaults(this, combinedDefaultsAndOptions);
  }
});

UI.Header = UI.Component.extend({
  defaults: {
    backButton: null,
    backButtonTitle: null,
    secondaryBarChildren: []
  }
});

App.Headers.Default = UI.Header.extend({
  options: {
    backButtonTitle: "App back",
    secondaryBarChildren: ["App child"]
  }
});

var header1 = new UI.Header({
  backButtonTitle: "Header 1 Back",
  secondaryBarChildren: ["Header 1 child"]
});

var header2 = new UI.Header({
  backButtonTitle: "Header 2 Back",
  secondaryBarChildren: ["Header 2 child"]
});

var header3 = new App.Headers.Default({
});

var header4 = new App.Headers.Default({
  backButtonTitle: "Overrided App Back"
});

header1.secondaryBarChildren.push('a child for header 1');

console.log(header1, header2, header3, header4);
Run Code Online (Sandbox Code Playgroud)

Bry*_*ark 1

我认为你想覆盖你的例子的初始化函数,但你有很多事情要做,所以我不确定;如果这个功能关闭了,请原谅我。我可能只是在清理我认为你正在尝试做的事情,使其成为一个更加“骨干”风格的系统。

从您的基本组件开始,如下所示:

UI.Component = Backbone.View.extend({
    defaults : { 'children' : [] },
    initialize : function (options) {
        _.defaults(options, this.defaults);
        _.keys(this.defaults).forEach(function(key) {
              this[key] = this.options[key];
        }.bind(this));
        Backbone.View.prototype.initialize.call(this, options);
    },
    add: function(child) {
        this.children.push(child);
    }
});
Run Code Online (Sandbox Code Playgroud)

然后你可以继续以类似的方式扩展它们,如下所示:

UI.Header = UI.Component.extend({
    defaults : { 
        'titleBarChildren' : [], 
        'secondaryBarChildren' : [], 
        'title' : '', 
        'backButtonTitle' : 'Back' 
    },
    initialize : function (options) {
        _.defaults(options, this.defaults);
        _.keys(this.defaults).forEach(function(key) {
              this[key] = this.options[key];
        }.bind(this));
        UI.Component.prototype.initialize.call(this, options);
    }
});
Run Code Online (Sandbox Code Playgroud)

以下是我在代码中尝试执行的操作的细分:

Defaults创建一个干净地保存所有默认属性的对象

    defaults : { 'children' : [] },
Run Code Online (Sandbox Code Playgroud)

初始化覆盖允许您继续在视图之间传递选项,但每个组件都使用您的defaults对象来填补空白。

    initialize : function (options) {
        // merges your defaults in with the options passed
        _.defaults(options, this.defaults);
        // loop through your required defaults for this view
        // assigning the attributes to the passed options
        _.keys(this.defaults).forEach(function(key) {
              this[key] = this.options[key];
        }.bind(this));
        // Finally pass all your options up the chain of inheritance
        UI.Component.prototype.initialize.call(this, options);
    },
Run Code Online (Sandbox Code Playgroud)