2012-11-20 43 views
6

這是我的第一個問題,所以我希望我不會搞砸。 我已經檢查過有關這個問題的其他主題,但他們沒有涵蓋我遇到的情況。以乾淨的方式擴展骨幹視圖和繼承選項

我正在Backbone之上建立一個庫來創建移動應用程序。 我將所有組件定義爲骨幹視圖的主要原因是因爲我想在滾動(隱藏東西/從DOM中移除東西)上進行內存優化。

讓我開始用defenition那將是最理想的情況

定義一個基類的其他組件使用,一些默認 屬性和我需要的每個組件上一些方便的方法。

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

    children: [], 

    add: function(child) { 
     this.children.push(child); 
    } 
}); 

定義組件的一些默認屬性

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

    titleBarChildren: [], 

    secondaryBarChildren: [], 

    title: '', 

    backButtonTitle: 'Back' 
}); 

製作一個默認的頭在我的應用程序

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

    titleBarChildren: [ 
     new UI.SegmentedController({ 
      children: [ 
       new UI.Button('Lame example') 
      ] 
     }) 
    ] 
}); 

使用使用我的導航欄

var homePageNavbar = new MyApp.Header.Default({ 
    title: 'Homepage' 
}); 

現在讓我們運行

而且想象我們得到如下的輸出

// 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 

這就是我想在最後得到的結果,然而,這需要一些魔術已經超出我的經驗。

在一個側面說明,我已經嘗試使用「選項」屬性爲我所有的自定義的東西,但問題是,當我創建多個視圖實例,選項是「共享」/引用彼此。

所以,現在我希望我將有更多的運氣與「viewOptions」的方法,然後重寫_configure method

Preferrably這是所有在UI.Component完成或它的孩子。 我不希望這個庫的用戶在標題defenition(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; 
    } 
}); 

我添加到我的所有組件這種新方法,並沒有把「共享」屬性在我的基礎對象(UI.Component),因爲我couln 「T把它打好。

UI.Header = UI.Component.extend({ 

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

    getDefaultOptions: function() { 
    return { 
     children: [] 
    }; 
    }, 
}); 

現在,我使用這樣的定義我的頭

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

我會保持它現在是這樣的,看看這個「解決方案」生存,並會報到。 如果你認爲你有一個更好的答案,毫不猶豫將它張貼=)

編輯

這是我最新的方法,使用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); 

回答

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); 
    } 
}); 

然後你就可以繼續他們在這樣類似的方式擴大:

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); 
    } 
}); 

這裏是我想要擊穿在代碼中執行:

默認值創建一個可以乾淨地保存所有默認屬性的對象

defaults : { 'children' : [] }, 

初始化覆蓋可以讓你繼續從視圖傳遞選項來查看,但每個組件使用您的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); 
    }, 
+0

感謝您參與此次活動,我肯定會玩這個並報告回來,那麼在兩個「組件」中添加初始化方法的原因是什麼?並且,UI.Component在初始化方法中調用自身是否正確? (UI.Component.prototype.initialize.call(此,選項);)Wouln't導致無限循環? – Vespakoen

+0

哦,對。在第一個View對象中,你需要運行它的initialize方法,而不是Component。很好,我會嘗試更新它。 –

+0

感謝您的,感謝您給我看的默認值:{}想法,它是一個真正的大開眼界。 由於我只需要3個級別的擴展,我建立了一個「blockDefaults」和普通的「默認值」,除此之外,可以在我的組件上設置「選項」,並在製作實例時覆蓋它們,我對它很滿意到目前爲止(請參閱我的最新編輯)。我會再睡一晚,明天我會看到我的想法=) – Vespakoen