【发布时间】:2016-07-07 18:29:27
【问题描述】:
所以这是一个我以前从未真正遇到过的奇怪的 KnockoutJS 问题。
我正在开发一个大量使用 Knockout 组件的应用程序。
在应用程序的一部分中,我有一个编辑器页面,该页面由 JSON 驱动的后端动态构建,并根据后端数据告诉它的内容,使用许多小部件填充前端页面。
示例 后端可能会发送
[{"widget": "textBox"},{"widget": "textBox"},{"widget": "comboBox"},{"widget": "checkBox"}]
这会导致前端构建一个包含
的页面<html>
....
<textbox></textbox>
<textbox></textbox>
<combobox></combobox>
<checkbox></checkbox>
....
</html>
每个自定义标签都是一个单独的 KnockoutJS 组件,编译为 AMD 模块并使用 RequireJS 加载,每个组件都基于相同的样板:
/// <amd-dependency path="text!application/components/pagecontrols/template.html" />
define(["require", "exports", "knockout", 'knockout.postbox', "text!application/components/pagecontrols/template.html"], function (require, exports, ko, postbox) {
var Template = require("text!application/components/pagecontrols/template.html");
var ViewModel = (function () {
function ViewModel(params) {
var _this = this;
this.someDataBoundVar = ko.observable("");
}
ViewModel.prototype.somePublicFunction = function () {
postbox.publish("SomeMessage", { data: "some data" });
};
return ViewModel;
})();
return { viewModel: ViewModel, template: Template };
});
组件相互通信并使用“Knockout Postbox”以 pub sub 方式与页面通信。
当我将它们放入页面时,我会在以下庄园中这样做:
<div data-bind="foreach: pageComponentsToDisplay">
<!-- ko if: widget == "textBox" -->
<textBox params="details: $data"></textBox>
<!-- /ko -->
<!-- ko if: widget == "comboBox" -->
<comboBox params="details: $data"></comboBox>
<!-- /ko -->
<!-- ko if: widget == "checkBox" -->
<checkBox params="details: $data"></checkBox>
<!-- /ko -->
</div>
其中 pageComponentsToDisplay 是一个简单的剔除可观察数组,我只是将从后端接收到的对象推送到:
pageComponentsToDisplay = ko.observableArray([]);
pageComponentsToDisplay(data);
“数据”在上面的 JSON 中显示
现在所有这些都很好用,但现在是 ODD 部分。
如果我必须“重新加载”页面,我只需
pageComponentsToDisplay = ko.observableArray([]);
清除数组,因此,我的所有组件也按预期从页面中消失,但是当我加载新数据时,再次使用:
pageComponentsToDisplay(data);
我的新组件按预期显示在屏幕上,但旧组件似乎仍然存在并在内存中处于活动状态,即使它们不可见。
我知道控件仍然存在的原因是,当我发出一条 PubSub 消息以向控件询问某些状态信息时,它们都回复了。
在我看来,当我清除数组时,当 KO 清除视图模型时,它实际上似乎并没有破坏旧副本。
此外,如果我再次刷新,我会得到 3 组组件响应,再次刷新是 4 组,并且按预期不断增加。
这是我第一次在淘汰赛中遇到这种行为,而且我多年来一直使用这种模式没有问题。
如果您想对整个项目的设置有一个很好的了解,我的 github 页面上有一个示例骨架布局:
https://github.com/shawty/dotnetnotts15
如果有人对这里可能发生的事情有任何想法,我很想听听。
作为最后一点,我实际上是使用 Typescript 开发所有这些,但由于这是一个运行时问题,我从 JS 的角度记录它。
问候 肖蒂
更新 1
因此,在进一步挖掘之后(感谢 cl3m 的回答,有了一点“新思维”),我向前迈进了一点。
在我最初的帖子中,我确实提到我正在使用 Ryan Niemeyer 出色的 PubSub 扩展来实现 Knockout 'ko postbox'。
事实证明,我的“组件”正在被处置和拆除,但为响应邮箱而创建的订阅处理程序却没有。
结果是,VM(或更具体地说,订阅在 VM 中使用的值)与邮箱订阅处理程序一起保存在内存中。
这意味着当我的主人广播一条消息询问组件值时,持有的引用会响应,然后是可见的活动组件。
我现在需要做的是找出一种处理这些订阅的方法,因为我直接使用邮箱,而不是将它们分配给我的模型中的可观察对象,这意味着我实际上没有 var 或对象引用来定位他们。
任务继续。
更新 2
查看我对以下问题的自我回答。
【问题讨论】:
-
您是否使用
ko.utils.domNodeDisposal.addDisposeCallback()方法在从DOM中删除相应元素后处理您的剔除组件? -
我不知道,我只是清除了数组,我假设它会自动拆除我的组件实例。我必须承认,但是当我在周五研究这个时,我遇到了提到它的文档,但还没有考虑使用它。简而言之,除非 KO 自动为我做,否则我不会。
-
我正在使用这种方法进行自定义绑定,但是我不会在组件上尝试它......
-
你用的和我一样的方法,还是你用的addDisposeCallBack?如果是后者,您介意发布样本吗?
-
我使用的是
addDisposeCallBack。请参阅我的答案中的示例。我不确定它会不会有多大帮助:S
标签: javascript knockout.js requirejs web-component