借助Knockout.js订阅动画一组对象?

时间:2015-01-08 19:11:14

标签: javascript jquery knockout.js observable

我花了最后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。对无关元素的单击绑定将此observable设置为false(如果它们都不显示)或添加/替换/删除,具体取决于应显示哪个。一次只能显示一个.manageOption

但是,只有当self.managementStatefalse转到 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);
        });
    }
}

从根本上说,这是因为我根本不理解“订阅”的概念。我自己编写绑定的经验很少。如何使用上面的订阅函数来跟踪observable的先前值,以及如何构建我的绑定以实现我需要的?

1 个答案:

答案 0 :(得分:1)

第一个问题是您在更新回调中设置订阅。更改某些依赖项时会调用更新函数。所以订阅beforechange事件为时已晚。此外,您还会在每次更改值后设置新订阅。您必须在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);
        });          
    }
}