Javascript ko可观测阵列在最后一个元素移除时未触发

Javascript ko可观测阵列在最后一个元素移除时未触发,javascript,knockout.js,Javascript,Knockout.js,我有一个带有元素的地图,显示当前正在加载的图层。我在一个击倒可观察数组中持有一个层名称列表。加载新图层时,它们将按预期显示。当层完成加载时,它们将按预期移除,最后一个除外。即使调试显示它绑定到的列表现在为空,也不会删除它 要初始化可观察对象,请执行以下操作: self.currentlyLoadingLayers = ko.observableArray([]); 即将加载图层时: self.layerLoadingStarted(layerName); 加载层时激发的事件: layer.e

我有一个带有元素的地图,显示当前正在加载的图层。我在一个击倒可观察数组中持有一个层名称列表。加载新图层时,它们将按预期显示。当层完成加载时,它们将按预期移除,最后一个除外。即使调试显示它绑定到的列表现在为空,也不会删除它

要初始化可观察对象,请执行以下操作:

self.currentlyLoadingLayers = ko.observableArray([]);
即将加载图层时:

self.layerLoadingStarted(layerName);
加载层时激发的事件:

layer.events.register('loadend', layer, function () {
    self.layerLoadingFinished(layerName);
});
以及被调用的函数:

self.layerLoadingStarted = function (layerName) {
    self.currentlyLoadingLayers.push(layerName);
};

self.layerLoadingFinished = function(layerName) {
    for (var i = self.currentlyLoadingLayers().length - 1; i >= 0; i--) {
        if (self.currentlyLoadingLayers()[i] === layerName) {
            self.currentlyLoadingLayers().splice(i, 1);
        }
    }
    //if (self.currentlyLoadingLayers().length === 0) self.currentlyLoadingLayers([]);
};
如果我取消注释上面函数中的最后一行,那么一切都正常。为什么需要这样做?数组现在为空这一事实不应该被自动观察到吗

我的绑定:

<div id="layersLoadingMessage" data-bind="visible: $root.currentlyLoadingLayers() && $root.currentlyLoadingLayers().length">
    <div data-bind="foreach: $root.currentlyLoadingLayers">
        <div data-bind="text: $data"></div>
    </div>
</div>

当添加或删除
observableArray
中的某个项目,或者更换整个集合时,Knockout将通知订阅者。但仅当通过
ObservalArray
对象而不是直接操纵底层数组时

因此,这将通知订阅者:

self.currentlyLoadingLayers.splice(i, 1)
这不会:

self.currentlyLoadingLayers().splice(i, 1)
这将:

self.currentlyLoadingLayers([])
请检查文档以了解更多信息

我在您的代码中添加了一些注释,并做了一些解释:

self.layerLoadingFinished = function(layerName) {
    for (var i = self.currentlyLoadingLayers().length - 1; i >= 0; i--) {
        if (self.currentlyLoadingLayers()[i] === layerName) {
            //this line modifies the underlying array directly bypassing ko's notifiers
            //change this to self.currentlyLoadingLayers.splice(i, 1)
            //to notify subscribers after each item is removed
            self.currentlyLoadingLayers().splice(i, 1);
        }
    }
    //this line uses self.currentlyLoadingLayers([]) which changes 
    //the underlying array through ko and will notify subscribers
    if (self.currentlyLoadingLayers().length === 0) self.currentlyLoadingLayers([]);
};

这是因为您正在绕过
observatarray
对象上的淘汰订阅操作
observatarray
的底层数组。谢谢,现在更清楚了。作为knockoutjs的新手(我继承了这个项目),我不理解
.splice
().splice
之间的区别。我想让我困惑的是,
.push
的通知正在清除以前用
()删除的项目。splice
使其看起来像
()。splice
正在通知订阅者。@AndyNichols没问题,伙计,很高兴我能帮忙:)