0

私が達成しようとしているのは、フィルタリングされた行の要素がDOMから削除されるのではなく非表示になるように、バインディングによって生成されたテーブル行を視覚的にフィルタリングすることです。foreach このアプローチにより、ユーザーがフィルター条件を変更したときのレンダリング パフォーマンスが大幅に向上します。これが、フィルター条件に応じて更新される計算された監視可能な配列に をバインドしたくない理由です。 このソリューションを、プロジェクトの他の場所で使用できる、すぐに使用できるビルディング ブロックにしたいと考えています。tr
foreach

私が Knockout に精通している限り、最善の方法はカスタム バインディングを実装することです。

このバインディングを使用するつもりだった方法は、次のようなものです。

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

whereは、次のように、現在の行が表示されるかどうかに応じて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フィルター関数は呼び出されません。
したがって、オブザーバブルは読み取られず、KO 依存関係追跡メカニズムは、このバインディングがビュー モデル内のオブザーバブルに依存していないと判断します。
また、フィルター オブザーバブル (filterFromDateおよびfilterDriver) の値が変更さupdateれると、 が再び呼び出されることはなく、フィルター処理全体が機能しません。

少なくとも関数がパラメーターとして値を待機するようにするフィルター関数への醜い呼び出しを行わないように、この実装(または問題へのアプローチ全体)を改善するにはどうすればよいundefinedですか?

4

1 に答える 1