敲除组件处置未调用
Knockout component dispose not called
我有一个自定义 KO 组件 address-input
ko.components.register('address-input', {
viewModel: { createViewModel: function ({}, componentInfo) {
var self = {};
self.dispose = function() {
// When removed by KO, dispose computeds and subscriptions
};
return self;
}},
template: 'address-input'
});
对应模板为地址-input.html
<div class`enter code here`="clearfix row">
<!-- elements come here -->
</div>
我的应用程序是一个 SPA 应用程序,其基本布局如下所示
A main.html 将包含 section.html,后者又包含 地址输入, html。在页面 nav 上,section.html 将被另一个 html 替换,依此类推。
html 部分通过 AJAX
加载
$j.ajax({
url: url,
success: function(htmlText) {
var $el = $j(element);
$el.html(htmlText);
ko.applyBindingsToDescendants(bindingContext, $el[0]);
},
cache: false,
mimeType: 'text/html-ko'
});
将来我可能会在地址输入组件中订阅一些可观察对象。当发生这种情况时,我希望在离开页面时调用 dispose 方法。但它现在没有发生。这里有什么问题?是 DOM 没有从内存中删除的情况吗?如果是这样,为什么?
您正在使用 jQuery 替换 DOM 树的一部分。 Knockout 无法知道删除了哪些元素,也无法在绑定模型上调用 dispose
。
使用 knockout 的 html
绑定到 add/remove 新部分或(不推荐)在调用 $el.html
.
之前调用 ko.cleanNode(element)
示例显示:
- 当您从 DOM 中手动删除组件时,不会通知 knockout 并且无法调用
dispose
- 当您使用常规绑定更改 DOM(例如
foreach
、if
、with
)敲除时 在必须删除内容时调用 dispose
- 当您调用
ko.cleanNode
时,knockout 将所有节点从它们的模型中分离出来,调用 dispose
,然后让您对剩余的 DOM 个节点执行您想要的操作。
ko.components.register('mycomponent', {
viewModel: function(params) {
this.dispose = () => console.log("Dispose called");
},
template: "<li>My Component</li>"
});
// Some example data to render a list
const comps = ko.observableArray([1, 2, 3, 4]);
// Remove straigt from the DOM without knockout...
const badRemove = () => document
.querySelector("mycomponent:last-child")
.remove();
const manualDetach = () => ko.cleanNode(document.querySelector("div"));
// Use knockout to alter the DOM
const goodRemove = () => comps.shift();
ko.applyBindings({ comps, badRemove, goodRemove, manualDetach });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="foreach: comps">
<mycomponent></mycomponent>
</div>
<button data-bind="click: badRemove">bad remove</button>
<button data-bind="click: goodRemove">good remove</button>
<button data-bind="click: manualDetach">clean node</button>
我有一个自定义 KO 组件 address-input
ko.components.register('address-input', {
viewModel: { createViewModel: function ({}, componentInfo) {
var self = {};
self.dispose = function() {
// When removed by KO, dispose computeds and subscriptions
};
return self;
}},
template: 'address-input'
});
对应模板为地址-input.html
<div class`enter code here`="clearfix row">
<!-- elements come here -->
</div>
我的应用程序是一个 SPA 应用程序,其基本布局如下所示
A main.html 将包含 section.html,后者又包含 地址输入, html。在页面 nav 上,section.html 将被另一个 html 替换,依此类推。
html 部分通过 AJAX
加载 $j.ajax({
url: url,
success: function(htmlText) {
var $el = $j(element);
$el.html(htmlText);
ko.applyBindingsToDescendants(bindingContext, $el[0]);
},
cache: false,
mimeType: 'text/html-ko'
});
将来我可能会在地址输入组件中订阅一些可观察对象。当发生这种情况时,我希望在离开页面时调用 dispose 方法。但它现在没有发生。这里有什么问题?是 DOM 没有从内存中删除的情况吗?如果是这样,为什么?
您正在使用 jQuery 替换 DOM 树的一部分。 Knockout 无法知道删除了哪些元素,也无法在绑定模型上调用 dispose
。
使用 knockout 的 html
绑定到 add/remove 新部分或(不推荐)在调用 $el.html
.
ko.cleanNode(element)
示例显示:
- 当您从 DOM 中手动删除组件时,不会通知 knockout 并且无法调用
dispose
- 当您使用常规绑定更改 DOM(例如
foreach
、if
、with
)敲除时 在必须删除内容时调用dispose
- 当您调用
ko.cleanNode
时,knockout 将所有节点从它们的模型中分离出来,调用dispose
,然后让您对剩余的 DOM 个节点执行您想要的操作。
ko.components.register('mycomponent', {
viewModel: function(params) {
this.dispose = () => console.log("Dispose called");
},
template: "<li>My Component</li>"
});
// Some example data to render a list
const comps = ko.observableArray([1, 2, 3, 4]);
// Remove straigt from the DOM without knockout...
const badRemove = () => document
.querySelector("mycomponent:last-child")
.remove();
const manualDetach = () => ko.cleanNode(document.querySelector("div"));
// Use knockout to alter the DOM
const goodRemove = () => comps.shift();
ko.applyBindings({ comps, badRemove, goodRemove, manualDetach });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="foreach: comps">
<mycomponent></mycomponent>
</div>
<button data-bind="click: badRemove">bad remove</button>
<button data-bind="click: goodRemove">good remove</button>
<button data-bind="click: manualDetach">clean node</button>