2013-07-11 89 views
2

我有一個html section元素,它具有綁定到ViewModel上項目集合的Knockout foreach。這可以很好地將集合的每個項目呈現在垂直向下的頁面上。我現在希望項目根據窗口大小將它們自己分組成行,因此項目出現在桌面瀏覽器的4行中,但移動設備上每行只有1行。使用Knockout.js創建組foreach

我確實通過在viewmodel中創建組並使視圖元素與foreach屬性綁定來實現此目的。這種方法的問題在於,我的視圖模型現在擁有了我會考慮的一些視圖邏輯,並直接引用窗口對象。哪一個不對,我不認爲。

我已經有一個單獨的js文件,它具有視圖特定的邏輯,也就是像'slideVisible'這樣的定製的Knockout綁定。如何將分組邏輯從我的viewmodel中移出並存入此文件中?我猜我不能使用Knockout的foreach綁定,如果分組沒有在視圖模型中完成?

回答

4

如果您需要在KO中動態執行此操作,那麼這裏是一個綁定示例,它包裝正常的綁定並創建一個即時計算,該計算返回基於「count」可觀察值的行/列的結構。

ko.bindingHandlers.foreachGroups = { 
    init: function(element, valueAccessor) { 
     var groupedItems, 
      options = valueAccessor(); 

     //create our own computed that transforms the flat array into rows/columns 
     groupedItems = ko.computed({ 
      read: function() { 
       var index, length, group, 
        result = [], 
        count = +ko.utils.unwrapObservable(options.count) || 1, 
        items = ko.utils.unwrapObservable(options.data); 

       //create an array of arrays (rows/columns) 
       for (index = 0, length = items.length; index < length; index++) { 
        if (index % count === 0) { 
         group = []; 
         result.push(group); 
        } 

        group.push(items[index]); 
       } 

       return result; 
      }, 
      disposeWhenNodeIsRemoved: element 
     }); 

     //use the normal foreach binding with our new computed 
     ko.applyBindingsToNode(element, { foreach: groupedItems }); 

     //make sure that the children of this element are not bound 
     return { controlsDescendantBindings: true }; 
    } 
}; 

你會用它喜歡:

<div data-bind="foreachGroups: { data: items, count: count }"> 
    <ul data-bind="foreach: $data"> 
     <li data-bind="text: $data"></li> 
    </ul> 
</div> 

這裏有一個例子:http://jsfiddle.net/rniemeyer/F48XU/

針對您的特殊情況下,雖然,我可能會:

  • 刪除count選項只是通過項目
  • init函數中創建您自己的count可觀察。
  • 添加一個resize事件處理程序,它可以運行您的邏輯並適當地更新count可觀察值。

它看起來是(填寫您的具體調整大小邏輯):

ko.bindingHandlers.foreachGroups = { 
    init: function(element, valueAccessor) { 
     var groupedItems, 
      data = valueAccessor(), 
      count = ko.observable(1); 

     ko.utils.registerEventHandler(window, "resize", function() { 
      //run your calculation logic here and update the "count" observable with a new value 
     }); 

     //create our own computed that transforms the flat array into rows/columns 
     groupedItems = ko.computed({ 
      read: function() { 
       var index, length, group, 
        result = [], 
        itemsPerRow = +ko.utils.unwrapObservable(count) || 1, 
        items = ko.utils.unwrapObservable(data); 

       //create an array of arrays (rows/columns) 
       for (index = 0, length = items.length; index < length; index++) { 
        if (index % itemsPerRow === 0) { 
         group = []; 
         result.push(group); 
        } 

        group.push(items[index]); 
       } 

       return result; 
      }, 
      disposeWhenNodeIsRemoved: element 
     }); 

     //use the normal foreach binding with our new computed 
     ko.applyBindingsToNode(element, { foreach: groupedItems }); 

     //make sure that the children of this element are not bound 
     return { controlsDescendantBindings: true }; 
    } 
}; 
+0

很不錯的,工作的享受。 – Dale

+0

請注意,給定表單中的解決方案將在分組點處創建新的綁定上下文,因此$ root和父上下文變得未定義。查看[這個問題]上的答案(http://stackoverflow.com/questions/34456889/knockout-custom-binding-handlers-root-is-undefined)來查看保留原始綁定上下文的修改。 – sjager