使用JavaScript手动逐步执行CSS动画

时间:2013-06-20 17:55:02

标签: javascript css html5 css3 css-animations

如果我有像这样的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只是一个例子 - 我希望能够用任何动画做到这一点。

5 个答案:

答案 0 :(得分:11)

使用内置动画:

不幸的是,没有

转换的内部不会暴露给JavaScript,因此您无法利用它来设置或获取数据。这是出于某种目的 - 如果数据暴露,则意味着效率降低,因为必须更新JavaScript事件队列。由于JS是单线程的,并且动画在一个单独的线程上运行,你很快就会失去它在一个单独的线程内部在编译代码中运行的好处。

然而,您可以进行自己的过渡。这涉及计算过渡。

这并不像听起来那么复杂,因为您只需使用插值公式来制作想要制作动画的内容:

current = source + (destination - source) * fraction;

例如,对于颜色,您可以将其与颜色分量一起使用。让我们假设我们的颜色对象包含属性rgb

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之间转换的示例功能。 风格可以是。 backgroundColorcolor等:

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

enter image description here

在源和命运之间的任意点手动设置转换,或为它们设置动画。

答案 1 :(得分:3)

你不能按照自己的意愿去做。

你唯一的可能性是在给定的延迟后改变游戏状态。

在你的情况下,由于动画持续0.5秒,为了使动画达到50%,你应该设置0.25秒的超时,然后设置动画播放状态:暂停。

当然,这不会完全达到50%,不要相信这种方法的精确度。

编辑

为webkit添加了演示:

fiddle

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-delayanimation-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)

是, 您可以覆盖动画的持续时间或时间。希望我明白你想做什么:

http://jsfiddle.net/SEHyW/

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);