0

我想要实现的是在视觉上过滤由foreach绑定生成的表行,其中被过滤掉的行的tr元素将被隐藏而不是从 DOM 中删除。
当用户更改过滤条件时,这种方法显着提高了渲染性能。这就是为什么我不希望将foreach其绑定到根据过滤条件更新的计算可观察数组。
我希望这个解决方案成为一个现成的构建块,我可以在项目的其他地方使用它。

据我熟悉的淘汰赛,最好的方法是实现自定义绑定。

我打算使用这个绑定的方式是这样的:

<tbody data-bind="foreach: unfilteredItems, visibilityFilter: itemsFilter">
    <tr>
    ...
    </tr>
</tbody>

根据当前行是否可见,itemsFilter返回的函数在哪里,如下所示:boolean

    self.itemsFilter = function (item) {
        var filterFromDate = filterFromDate(), // Observable
            filterDriver = self.filterDriver(); // Observable too

        return item && item.Date >= filterFromDate && (!filterDriver || filterDriver === item.DriverKey);
    };

这是我到目前为止的绑定实现:

/*
 * Works in conjunction with the 'foreach' binding and allows to perform fast filtering of generated DOM nodes by
 * hiding\showing them rather than inserting\removing DOM nodes.
*/
ko.bindingHandlers.visibilityFilter = {
    // Ugly thing starts here
    init: function (elem, valueAccessor) {
        var predicate = ko.utils.unwrapObservable(valueAccessor());

        predicate();
    },
    // Ugly thing ends
    update: function (elem, valueAccessor) {
        var predicate = ko.utils.unwrapObservable(valueAccessor()),
            child = ko.virtualElements.firstChild(elem),
            visibleUpdater = ko.bindingHandlers.visible.update,
            isVisible,
            childData,
            trueVaueAccessor = function () { return true; },
            falseVaueAccessor = function () { return false; };

        while (child) {
            if (child.nodeType === Node.ELEMENT_NODE) {
                childData = ko.dataFor(child);

                if (childData) {
                    isVisible = predicate(childData, child);
                    visibleUpdater(child, isVisible ? trueVaueAccessor : falseVaueAccessor);
                }
            }

            child = ko.virtualElements.nextSibling(child);
        }
    }
};
ko.virtualElements.allowedBindings.visibilityFilter = true;

您是否看到init了谓词调用的丑陋部分而没有将对象传递给它?

如果没有这个,如果foreach在第一次 Knockout 调用该update方法时没有由绑定生成的行,则不会调用itemsFilterfilter 函数。
因此,不会读取任何可观察对象,并且 KO 依赖跟踪机制决定此绑定不依赖于我的视图模型中的任何可观察对象。
并且当过滤器可观察对象 (filterFromDatefilterDriver) 的值发生更改时,update将永远不会再次调用 并且整个过滤器不起作用。

我怎样才能改进这个实现(或解决问题的整个方法),以免对过滤器函数进行丑陋的调用,这至少使函数等待一个undefined值作为参数?

4

1 回答 1

2

您可以visible在 上使用绑定并将其绑定到作为参数tr的函数调用的结果。$data下面是一个小演示。您选择的任何值都会从表格中过滤掉。

var vm = {
  rows: ko.observableArray(['One', 'Two', 'Three']),
  selected: ko.observable('One'),
  isVisible: function(row) {
    return row !== vm.selected();
  }
};

ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<select data-bind="options:rows, value:selected"></select>
<table border="1" data-bind="foreach:rows">
  <tr data-bind="visible:$parent.isVisible($data)">
    <td data-bind="text:$data"></td>
  </tr>
</table>

于 2015-09-21T00:05:46.273 回答