我有一个简单的应用程序,有两个视图,一个“app”模型和两个视图模型。我有兴趣研究如何取消绑定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 -->
在app模型中,初始化后,将加载视图模型。每个视图模型都有一个简单的模板属性,该属性是一个引用要呈现的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看到的光消除机制的一部分)
我发现当我在两个主视图之间切换时(每次渲染时都会调用此示例视图的viewDidRender),上面的body click处理程序会多次绑定。
我认为这是一个JavaScript内存泄漏。行踪应该清理这些绑定吗?我可以叫$(“html”)。off(...)等......但是在哪里?模板绑定的beforeRemove事件不会为纯模板项调用....仅适用于foreach绑定。
我可以在所有子视图模型中创建另一个方法,如“viewWillHide”,所以每次将新视图推送到app模型的ViewModel属性中时,我都可以尝试调用视图模型上的viewWillHide方法。这会奏效。但是,应用程序比我在这里展示的更复杂。实际上存在视图模型和嵌套模板的层次结构。
手动操作是一种选择;与模板绑定的afterRender没有相反的情况,这似乎很奇怪。
那你会怎么做?手动方法?即使它会在整个视图模型层次结构中引起一连串的更改,以便将viewWillHide方法从顶层(app model)向下传播到较小的视图模型。
由于
答案 0 :(得分:0)
尝试使用以下代码取消绑定jQuery事件
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
//Do cleanup
});
编辑:演示如何包装绑定的小提琴
问题是,绑定到模板绑定的div上的addDisposeCallback不会触发回调,因为该元素永远不会更改,其中的元素会在模板更改时发生更改。
此处回调将被称为http://jsfiddle.net/d6cJG/1/