我希望在某些属性随我的挖空模型(特别是移动)而改变时应用动画。我需要这些动画是同步的,如果有多个动画会让用户感到非常困惑。
我想使用敲除自定义绑定来执行此操作,因为它应该使我的代码更容易理解,但如果我这样做,我无法为jquery动画提供回调函数。我知道由于javascript的限制,我不能拥有真正的同步行为,但我无法弄清楚如何伪造它。
我想要的行为: http://jsfiddle.net/3fLvpxLc/2/
$("#e1").animate({left: 50}, "slow", function() {
// more animations
}
具有同步问题的版本: http://jsfiddle.net/hrwsd1z3/1/
ko.bindingHandlers.position = {
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor();
var valueUnwrapped = ko.unwrap(value);
$(element).animate({left: valueUnwrapped}, "slow");
}
}
答案 0 :(得分:2)
jQuery queues是你的朋友。使用它们,您可以序列化异步动画。
通常它们会隐式用于您对一个元素执行的所有动画效果,即绑定到动画元素本身:
$("element").show("slow").animate({left: 25});
但你也可以明确地使用它们。 queue
向队列添加动画,next
回调将下一个动画队列出来(您可以方便地将其作为complete
处理程序传递)。这样你可以将动画绑定到不同的元素而不是动画元素:
$("#container").queue(function (next) {
$("element").show("slow", next);
}
$("#container").queue(function (next) {
$("element").animate({left: 25}, next);
}
凭借这些知识,任务变得简单:
ko.bindingHandlers.syncPosition = {
init: function(element, valueAccessor) {
var newPosition = ko.toJS(valueAccessor());
// set element to its initial position
$(element).css(newPosition);
},
update: function(element, valueAccessor) {
var newPosition = ko.toJS(valueAccessor());
// queue position update as animation to a common element, e.g. the body
$(document.body).queue(function( next ) {
$(element).animate(newPosition, "slow", next);
});
}
};
function Item(id, top, left) {
this.id = ko.observable(id);
this.position = {
top: ko.observable(top),
left: ko.observable(left)
};
}
function VM(params) {
var self = this;
self.elements = ko.observableArray([
new Item("e1"),
new Item("e2"),
new Item("e3")
]);
}
var vm = new VM();
ko.applyBindings(vm);
vm.elements()[0].position.left(50);
vm.elements()[1].position.left(75);
vm.elements()[2].position.left(25);
vm.elements()[1].position.left(125);
vm.elements()[2].position.top(10);
vm.elements()[1].position.top(20);
vm.elements()[0].position.top(30);
vm.elements()[0].position.left(0);
vm.elements()[1].position.left(0);
vm.elements()[2].position.left(0);

div.container {
position: relative;
}
div.container > div {
width: 20px;
height: 20px;
position: absolute;
}
#e1 {
background-color: blue;
}
#e2 {
background-color: red;
}
#e3 {
background-color: green;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="container" data-bind="foreach: elements">
<div data-bind="syncPosition: position, attr: {id: id}"></div>
</div>
&#13;