在 Knockout.js 订阅的帮助下为一组对象设置动画?
Animating a group of objects with the help of a Knockout.js subscription?
我花了过去 6 个小时试图解决这个问题,但我找不到关于 Knockout.js 中订阅如何工作的文档,现在它已从 "mildly annoying" 类别中移出至 "downright frustrating"。
我想要完成什么?
我需要为 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.managementState
从 从 false
或 到 [=36] 时,才会出现 slideUp 或 slideDown 效果=] false
。因此,我不仅需要知道 self.managementState
的当前值,还需要知道之前的值。如果值从 add
更改为 remove
,我不需要为元素设置动画,更改会立即发生。
我试过的
为了解决这个问题,我一直想构建一个名为 slideSwitcher
的自定义绑定,它使用我描述的上述逻辑进行操作,而且我还发现这部分代码应该会获取先前的值一个可观察的:
function subscribeToPreviousValue(observable, fn) {
observable.subscribe(fn, this, 'beforeChange');
}
但我无法在自定义绑定中的 update
函数中很好地发挥它的作用,它总是 returns 错误的结果(例如,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);
});
}
}
从根本上说,这是因为我根本不理解 'subscription' 的概念,而且我自己编写绑定的经验也很少。我如何使用上面的订阅函数来跟踪一个可观察对象的先前值,我应该如何构建我的绑定来实现我需要的?
第一个问题是您在更新回调中设置了订阅。当某些依赖项发生更改时,将调用更新函数。所以订阅 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);
});
}
}
我花了过去 6 个小时试图解决这个问题,但我找不到关于 Knockout.js 中订阅如何工作的文档,现在它已从 "mildly annoying" 类别中移出至 "downright frustrating"。
我想要完成什么?
我需要为 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.managementState
从 从 false
或 到 [=36] 时,才会出现 slideUp 或 slideDown 效果=] false
。因此,我不仅需要知道 self.managementState
的当前值,还需要知道之前的值。如果值从 add
更改为 remove
,我不需要为元素设置动画,更改会立即发生。
我试过的
为了解决这个问题,我一直想构建一个名为 slideSwitcher
的自定义绑定,它使用我描述的上述逻辑进行操作,而且我还发现这部分代码应该会获取先前的值一个可观察的:
function subscribeToPreviousValue(observable, fn) {
observable.subscribe(fn, this, 'beforeChange');
}
但我无法在自定义绑定中的 update
函数中很好地发挥它的作用,它总是 returns 错误的结果(例如,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);
});
}
}
从根本上说,这是因为我根本不理解 'subscription' 的概念,而且我自己编写绑定的经验也很少。我如何使用上面的订阅函数来跟踪一个可观察对象的先前值,我应该如何构建我的绑定来实现我需要的?
第一个问题是您在更新回调中设置了订阅。当某些依赖项发生更改时,将调用更新函数。所以订阅 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);
});
}
}