敲除绑定中的同步动画
Sychronous animations in knockout binding
我想在某些属性随我的击倒模型(特别是运动)发生变化时应用动画。我需要这些动画是同步的,如果有多个动画在进行,用户会感到非常困惑。
我想使用 knockout 自定义绑定来执行此操作,因为它应该使我的代码更易于理解,但如果这样做,我无法为 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");
}
}
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>
我想在某些属性随我的击倒模型(特别是运动)发生变化时应用动画。我需要这些动画是同步的,如果有多个动画在进行,用户会感到非常困惑。
我想使用 knockout 自定义绑定来执行此操作,因为它应该使我的代码更易于理解,但如果这样做,我无法为 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");
}
}
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>