Mvvm 使用Knockout.js foreach创建组

Mvvm 使用Knockout.js foreach创建组,mvvm,knockout.js,Mvvm,Knockout.js,我有一个html节元素,它有一个Knockout-foreach绑定到viewmodel上的一个项目集合。这可以很好地将集合中的每个项呈现到垂直向下的div上。现在,我希望项目根据窗口大小按行分组,这样项目在桌面浏览器上显示为4行,但在移动设备上每行仅显示1行 实际上,我是通过在viewmodel中创建组并使用foreach将我的视图元素绑定到此groups属性来实现这一点的。这个方法的问题是,我的View模型现在有了我将要考虑的一组视图逻辑,并直接引用窗口对象。我认为这是不对的 我已经有了一个

我有一个html节元素,它有一个Knockout-foreach绑定到viewmodel上的一个项目集合。这可以很好地将集合中的每个项呈现到垂直向下的div上。现在,我希望项目根据窗口大小按行分组,这样项目在桌面浏览器上显示为4行,但在移动设备上每行仅显示1行

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


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

如果需要在KO中动态执行此操作,那么下面是一个绑定示例,它包装了正常的foreach绑定,并创建了一个动态计算的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 };
    }
};

如果需要在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 };
    }
};

注意,给定形式的解决方案将在分组时创建一个新的绑定上下文,因此$root和父上下文将变得未定义。查看上的答案以查看保留原始绑定上下文的修改。请注意,给定形式的解决方案将在分组时创建新的绑定上下文,因此$root和父上下文将变得未定义。查看上的答案,查看保留原始绑定上下文的修改。
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 };
    }
};