1 つの「アプリ」モデルと 2 つのビュー モデルの 2 つのビューを持つ単純なアプリがあります。jQuery イベントのバインドを解除する方法に興味があります。
アプリ ビュー モデルには次のプロパティがあります。
var self = this;
self.viewModel = ko.observable(null);
最も重要な HTML スニペットはマスター テンプレートにあり、それは次のとおりです。
<!-- ko if: viewModel -->
<div data-bind="template:{name:viewModel().template, data:viewModel(), afterRender: viewModel().viewDidRender}"></div>
<!-- /ko -->
アプリ モデルでは、初期化の後、ビュー モデルが読み込まれます。各ビュー モデルには、レンダリングする html テンプレートを参照する文字列である単純なテンプレート プロパティがあります。テンプレート宣言のデータ項目は、knockoutjs コンテキストを現在のビュー モデルに設定します。afterRender バインディングにより、ViewModel の viewDidRender メソッドが (コンテナーの html 要素をパラメーターとして) 呼び出されることが保証されます。
これは、次のことができることを意味します。
self.viewDidRender = function (parentElement) {
self.containerElement = parentElement;
$("html").on("click", function (event) {
var elements = $(event.target).parents();
for (var i = 0; i < elements.length; i++)
if (elements[i] == self.containerElement[0] || elements[i] == self.containerElement) {
alert("the target exists within the parent element");
return;
}
self.open(false);
});
};
html 要素のクリック イベントをインターセプトする必要があります。ターゲットがサブビューの親要素内にある場所でイベントが発生した場合は、イベントを無視します。それ以外の場合は、'open' を false に設定します (これは、実際には iOS の PopOvers で見られる簡単な非表示メカニズムの一部です)。
2 つのメイン ビューを切り替えると (この例のビューの viewDidRender は、レンダリングされるたびに呼び出されます)、上記のボディ クリック ハンドラーが複数回バインドされていることがわかりました。
これは JavaScript のメモリ リークだと思います。これらのバインディングはどこでクリーンアップする必要がありますか? $("html").off(...) などを呼び出すことができますが、どこで? テンプレート バインディングの beforeRemove イベントは、純粋なテンプレート アイテムに対しては呼び出されません。foreach バインディングに対してのみです。
「viewWillHide」のようなすべてのサブビュー モデル内に別のメソッドを作成できるので、新しいビューがアプリ モデルの ViewModel プロパティにプッシュされるたびに、ビュー モデルで viewWillHide メソッドを呼び出すことができます。これはうまくいくでしょう。ただし、アプリケーションはここで説明するよりも複雑です。実際には、ビュー モデルとネストされたテンプレートの階層があります。
手動で行うことはオプションです。テンプレート バインディングの afterRender に反対がないのは奇妙に思えます。
それで、あなたは何をしますか?手動アプローチ?viewWillHide メソッドを最上位 (アプリ モデル) から小さなビュー モデルまで階層に伝播するために、ビュー モデル階層全体に一連の変更が発生しますが。
ありがとう