2012-12-28 86 views
3

我有一個樹的類別,我想做Backbone.js使用而不是使用jQuery或在服務器端進行渲染。我有描述爲模板以下突破:如何在Backbone.js中呈現嵌套視圖?

<li> 
    <select class="categories"> 
     <option value="">Select</option> 
    </select> 
    <input class="edit" type="button" value="Edit"> 
    <input class="add" type="button" value="Add"> 
</li> 

我分別呈現爲內視圖標籤select。當我改變選擇時,我需要從服務器獲取嵌套類別,並使用上面包裝在標籤ul中的模板將它們附加到標籤li。在外觀上,我創建了內部視圖,並在編輯和添加時單擊監聽事件。當嵌套層次超過一層時,我遇到了最後一個事件的麻煩,因爲它們是嵌套層次的等同時間。我究竟做錯了什麼?

下面的代碼片段展示了我如何與外部和內部意見的工作:

var CategoriesInnerView = Backbone.View.extend({ 
     tagName:  'select', 
     initialize: function(){ 
      _.bindAll(this,'addOne','addAll'); 
      this.collection.bind('reset',this.addAll); 
     }, 
     addOne:  function(category){ 
      this.$el.append(new CategoryView({model:category}).render().el); 
     }, 
     addAll:  function(){ 
      this.collection.each(this.addOne); 
     }, 
     events:  { 
      'change':'changeSelected' 
     }, 
     changeSelected:function(){ 
      var children = new Categories(); 
      children.url = 'categories/' + this.$el.val(); 

      var childrenView = new CategoriesOuterView({collection:children}); 
      this.$el.parent().find('ul').remove(); 
      this.$el.parent().append(childrenView.render().el); 

      children.fetch(); 
     } 
    }); 

    var CategoriesOuterView = Backbone.View.extend({ 
     tagName: 'ul', 
     template: _.template($('#categories-template').html()), 
     initialize:function(){ 
      this.inner = new CategoriesInnerView({collection:this.collection}); 
     }, 
     render: function(){ 
      this.$el.html(this.template); 

      this.inner.setElement(this.$('select')).render(); 

      return this; 
     }, 
     events: { 
      'click .edit':'edit', 
      'click .add': 'add' 
     }, 
     edit: function(){ 
      this.renderForm(this.collection.get(this.inner.$el.val())); 
     }, 
     add: function(){ 
      this.renderForm(new Category()); 
     }, 
     renderForm:function(category){ 
      // some code to render the form 
     } 
    }); 
+0

「的Backbone.js的,而不是使用jQuery 「,Backbone沒有任何內置的渲染功能。 – Prinzhorn

+0

是的,我知道。我錯了。 –

回答

3

設置嵌套視圖時,必須考慮到事件會冒泡DOM樹並且Backbone在view.el級別處理DOM事件的事實。這意味着,在您的方案中,如果讓事件沿層次結構上升,則嵌套節點也會觸發父節點中的事件。

的演示中看到http://jsfiddle.net/PX2PL/

一個簡單的解決辦法是停止事件傳播中的回調

var CategoriesOuterView = Backbone.View.extend({ 
    events: { 
     'click .edit':'edit', 
     'click .add': 'add' 
    }, 
    edit: function(e) { 
     e.stopPropagation(); 
     this.renderForm(this.collection.get(this.inner.$el.val())); 
    }, 
    add: function(e) { 
     e.stopPropagation(); 
     this.renderForm(new Category()); 
    } 
} 

和更新的演示http://jsfiddle.net/PX2PL/1/

+0

感謝您的回答,我已經以相同的方式解決了它。 –

2

我們真的需要顯得有些代碼的正確回答這個問題,但它聽起來像是一兩件事情正在發生:

1)你是在相同的元素實例化視圖多次

2)你的事件選擇過於寬泛

無覆蓋,但實際上看到你的觀點(的相關部分),這很難說更多。


切向相關旁註

順便說一句,當你有這樣的事情,有兩種基本方法可以採取:

1)你可以有你的父視圖中創建子並將事件處理放在子視圖上2)你可以讓你的父視圖創建子視圖,也可以不創建子視圖(它可以創建所有的HTML本身),並將事件處理放在其上。

#1的優點是簡單:您的事件處理程序可以引用this來引用相關視圖。然而,如果你不得不把它放大得太多,那麼#1有一個問題:數以百萬計的視圖,每個視圖都有自己的事件處理程序,這會損害性能。因此,如果性能是/將是重要的,那麼#2會更好,因爲你只做一組事件連接。但是,事件處理程序必須更加智能化,因爲他們必須根據提供的事件(即#1方法中的e.target,與this)找出他們的工作內容。

+0

對於它的價值,我有4-5級嵌套的意見,而路線1總是非常簡單並且易於實施。 – asawyer

+0

從理論上說,不管你有多少層次的嵌套,如果你採取方法#1,它應該仍然非常簡單和容易實現。方法#2也不難(比#1更難)。但當然(正如你發現的那樣),魔鬼絕對是在細節中。 – machineghost

+0

我加了上面的代碼片段,請看。 –