我花了最后6个小时来尝试解决此问题,但关于Knockout.js中的订阅如何工作的文献很少,以至于现在它已从“轻度烦人”类别转移到“彻底令人沮丧”类别。
我想完成什么?
我需要为DOM的一部分设置动画,以使其根据需要上下滑动。这是以这种方式动画化的DOM的一般结构:
<section id="add" class="manageOption">
</section>
<section id="replace" class="manageOption">
</section>
<section id="remove" class="manageOption">
</section>
每个
.manageOption
具有相同的大小和尺寸,并且看起来非常相似。我的ViewModel中有一个名为self.managementState
的观察对象,该对象最初设置为false
。如果不显示任何元素,则对不相关元素的单击绑定会将此可观察值设置为false,或者根据应显示的内容将其添加/替换/删除。一次只能显示一个.manageOption
。但是,仅当
self.managementState
从false
变为false
时,才会发生slideUp或slideDown效果。因此,我不仅需要知道self.managementState
的当前值,还需要知道前一个值。如果值从add
更改为remove
,则无需为元素设置动画,更改将立即发生。我尝试过的
为了解决这个问题,我一直想构建一个名为
slideSwitcher
的自定义绑定,该绑定使用我已经描述的上述逻辑进行操作,并且我还发现这部分代码应该获取可观察对象的先前值:function subscribeToPreviousValue(observable, fn) {
observable.subscribe(fn, this, 'beforeChange');
}
但是我无法在自定义绑定中的
update
函数中很好地发挥它的作用,它总是返回错误的结果(例如,false已更改为false)。ko.bindingHandlers.slideSwitcher = {
update: function (element, valueAccessor) {
var observable = valueAccessor();
var currentVal = ko.utils.unwrapObservable(valueAccessor());
subscribeToPreviousValue(observable, function (previous) {
console.log('value changed from', previous, 'to', currentVal);
});
}
}
从根本上讲,这是因为我根本不了解“订阅”的概念,而且我自己编写绑定的经验很少。如何使用上面的订阅函数来跟踪可观察对象的先前值,以及如何构造绑定以实现所需的内容?
最佳答案
第一个问题是您在更新回调中设置了订阅。更改某些依赖项时将调用更新函数。因此,订阅更改前事件为时已晚。此外,您还需要在每次更改值后设置新的订阅。您必须在init函数中订阅该值。
我喜欢subscribeChanged函数(Get previous value of an observable in subscribe of same observable-第二个答案),它很好而且很清楚...
ko.subscribable.fn.subscribeChanged = function (callback) {
var oldValue;
this.subscribe(function (_oldValue) {
oldValue = _oldValue;
}, this, 'beforeChange');
this.subscribe(function (newValue) {
callback(newValue, oldValue);
});
};
您可以如下编写绑定
ko.bindingHandlers.slideSwitcher = {
init: function (element, valueAccessor) {
var observable = valueAccessor();
observable.subscribeChanged(function (newValue, oldValue) {
console.log('value changed from', oldValue, 'to', newValue);
});
}
}