2

我有一个 html 部分元素,它有一个 Knockout foreach 绑定到我的视图模型上的项目集合。这很好地将集合的每个项目呈现到页面垂直下方的 div 上。我现在希望这些项目根据窗口大小按行分组,因此项目出现在桌面浏览器上的 4 行中,但在移动设备上每行只有 1 个。

实际上,我确实通过在视图模型中创建组并将我的视图元素与 foreach 绑定到此组属性来实现这一点。这种方法的问题是我的视图模型现在有我认为的一堆视图逻辑,并直接引用窗口对象。我不认为这是不对的。

我已经有一个单独的 js 文件,其中包含特定的视图逻辑,即针对“slideVisible”之类的自定义 Knockout 绑定。如何将分组逻辑从我的视图模型中移出并移到此文件中?我猜如果未在视图模型中完成分组,我将无法使用 Knockout 的 foreach 绑定?

4

1 回答 1

4

如果您需要在 KO 中动态执行此操作,那么这里是一个绑定示例,它包装了普通foreach绑定并动态创建了一个计算,该计算返回一个基于“计数”可观察的具有行/列的结构。

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选项并传入项目
  • 在函数中创建自己的countobservable 。init
  • 添加一个resize事件处理程序来运行您的逻辑并count适当地更新 observable。

它可能看起来像(填写您的特定调整大小逻辑):

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 };
    }
};
于 2013-07-11T14:17:09.720 回答