如果我有像这样的CSS关键帧动画
@keyframes flash-red {
50% {
background: #f00;
}
}
#goflash.anm-flash {
animation-name: flash-red;
animation-duration: .5s;
background: rgba(255, 0, 0, 0);
}
然后我总是可以像这样触发动画:
var gf = document.querySelector("#goflash");
gf.classList.remove("anm-flash");
setTimeout(function() {
gf.classList.add("anm-flash");
}, 50);
有没有办法覆盖动画持续时间/动画定时功能依赖于JavaScript?我希望能够说gf.animate("flash-red", "50%")
之类的内容,以使gf
红色的背景,或gf.animate("flash-red", "75%")
使背景更像rgba(255, 0, 0, .5)
。
理想情况下,相同的技术适用于过渡。 gf.transitionTo("new-class", "50%")
会将元素显示为中途转换。
显然flash-red
只是一个例子 - 我希望能够用任何动画做到这一点。
答案 0 :(得分:11)
使用内置动画:
不幸的是,没有
转换的内部不会暴露给JavaScript,因此您无法利用它来设置或获取数据。这是出于某种目的 - 如果数据被暴露,则意味着效率降低,因为必须更新JavaScript事件队列。由于JS是单线程的,并且动画在一个单独的线程上运行,你很快就会失去它在一个单独的线程内部在编译代码中运行的好处。
然而,您可以进行自己的过渡。这涉及计算过渡。
这并不像听起来那么复杂,因为您只需使用插值公式来制作想要制作动画的内容:
current = source + (destination - source) * fraction;
例如,对于颜色,您可以将其与颜色分量一起使用。让我们假设我们的颜色对象包含属性r
,g
,b
:
var color1 = {r: 100, g: 200, b: 55}; //some random color
var color2 = {r: 0, g: 100, b: 100};
var fraction = 0.5; //0-1
这里当前的RGB将是:
r = color1.r + (color2.r - color1.r) * fraction;
g = color1.g + (color2.g - color1.g) * fraction;
b = color1.b + (color2.b - color1.b) * fraction;
对于职位:
var pos1x = 100;
var pos1y = 100;
var pos2x = 500;
var pos2y = 250;
var fraction = 1; //0-1
posX = pos1x + (pos2x - pos1x) * fraction;
posY = pos1y + (pos2y - pos1y) * fraction;
等等。
通过制作包装函数,您可以轻松地计算这些函数,甚至可以将它们放在一个循环中来为它们设置动画。
用于设置颜色1和颜色2之间转换的示例功能。
风格可以是。 backgroundColor
,color
等:
function setColor(element, style, color1, color2, fraction) {
var r = color1.r + (color2.r - color1.r) * fraction;
var g = color1.g + (color2.g - color1.g) * fraction;
var b = color1.b + (color2.b - color1.b) * fraction;
element.style[style] = 'rgb(' + (r|0) + ',' + (g|0) + ',' + (b|0) + ')';
}
(r|0
只是截断小数部分。)
对于职位,例如:
var pos1 = {x: 0, y: 0};
var pos2 = {x: 200, y: 0};
function setPosition(element, pos1, pos2, fraction) {
var x = pos1.x + (pos2.x - pos1.x) * fraction;
var y = pos1.y + (pos2.y - pos1.y) * fraction;
element.style.left = x + 'px';
element.style.top = y + 'px';
}
一个简单的演示(使用Chrome或Aurora 23查看滑块,滑块出现在FF 23的下一个版本中)。
<强> Fiddle 强>
在源和命运之间的任意点手动设置转换,或为它们设置动画。
答案 1 :(得分:3)
你不能按照自己的意愿去做。
你唯一的可能性是在给定的延迟后改变游戏状态。
在你的情况下,由于动画持续0.5秒,为了使动画达到50%,你应该设置0.25秒的超时,然后设置动画播放状态:暂停。
当然,这不会完全达到50%,不要相信这种方法的精确度。
为webkit添加了演示:
HTML很简单
<div id="goflash">TEST</div>
<input type="button" value="animate" onclick="animate()">
CSS简单
#goflash {
width: 200px;
height: 200px;
left: 35px;
top: 35px;
position: absolute;
background-color: red;
}
.anm-flash {
-webkit-animation-name: flash;
-webkit-animation-duration: 5s;
-webkit-animation-timing-function: linear;
-webkit-animation-iteration-count: 1;
}
@-webkit-keyframes flash {
from { -webkit-transform: rotate(0deg);
background-color: red; }
50% { -webkit-transform: rotate(120deg);
background-color: yellow;}
to { -webkit-transform: rotate(360deg);
background-color: red;
}
}
javascript是您提供的扩展程序:
function animate () {
var gf = document.querySelector("#goflash");
gf.classList.remove("anm-flash");
setTimeout(function() {
gf.classList.add("anm-flash");
gf.style.webkitAnimationPlayState = "running";
}, 50);
setTimeout(function() {
gf.style.webkitAnimationPlayState = "paused";
}, 2550);
}
您可以在小动作暂停后启动动画,并在启动后计算延迟,然后停止它。 由于动画时间为5秒,初始延迟为50毫秒,因此第二延迟必须为(5000/2)+ 50。 由于您现在已将播放状态设置为暂停,因此无需重新运行动画,您必须将状态设置为再次运行。
答案 2 :(得分:2)
假设您的元素gf
只有一个动画,您只需使用animation-delay
和animation-play-state
控制它:
gf.__proto__.animate = function(percent) {
this.style["animation-play-state"] = "paused";
this.style["animation-delay"] = (
(parseFloat(this.style["animation-duration"] || 1) * -percent) + "s"
);
};
您可以获得如下计算样式:
window.getComputedStyle(gf).background
以任何速度逐步完成:
(function animation(time) {
gf.animate( ((time || 0) % desireSpeed ) / desireSpeed );
requestAnimationFrame(animation);
})();
注意:这将覆盖来自css的动画延迟,因此您可能希望将其保留在可变量中并将其添加为gf.__proto__.animate()
中的偏移量。
答案 3 :(得分:1)
也许使用CSS DOM来解析动画的意图(如果可能的话?)然后用JavaScript重构一切。
但那并不奇怪!
我想知道CSS预处理器是否有助于构建这样的代码。这在理论上非常重要。
答案 4 :(得分:1)
是, 您可以覆盖动画的持续时间或时间。希望我明白你想做什么:
var gf = document.querySelector("#goflash"),
animationDuration = '1s'
gf.classList.remove("anm-flash");
setTimeout(function() {
gf.classList.add("anm-flash");
gf.style["-webkit-animation-duration"] = animationDuration;
}, 1000);