敲除组件处置未调用

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(例如 foreachifwith)敲除时 在必须删除内容时调用 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>