我想要实现的是在视觉上过滤由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
方法时没有由绑定生成的行,则不会调用itemsFilter
filter 函数。
因此,不会读取任何可观察对象,并且 KO 依赖跟踪机制决定此绑定不依赖于我的视图模型中的任何可观察对象。
并且当过滤器可观察对象 (filterFromDate
和filterDriver
) 的值发生更改时,update
将永远不会再次调用 并且整个过滤器不起作用。
我怎样才能改进这个实现(或解决问题的整个方法),以免对过滤器函数进行丑陋的调用,这至少使函数等待一个undefined
值作为参数?