如何使用js捕获css3动画

css3动画功能强大,但是不像js,没有逐帧控制,但是可以通过js事件来确定任何动画的状态。

下面是一段css3动画代码:

#anim.enable{
-webkit-animation: flash 1s ease 3;
-moz-animation: flash 1s ease 3;
-ms-animation: flash 1s ease 3;
-o-animation: flash 1s ease 3;
animation: flash 1s ease 3;
} /* animation */
@-webkit-keyframes flash {
50% { opacity:; }
} @-moz-keyframes flash {
50% { opacity:; }
} @-ms-keyframes flash {
50% { opacity:; }
} @-o-keyframes flash {
50% { opacity:; }
} @keyframes flash {
50% { opacity:; }
}

上面动画的效果是:当id为anim的元素加上enable的class的时候,执行动画flash 3 次,每次执行事件是1s。

当触发动画的时候,有三种类型的事件触发:

1、animationstart

var anim = document.getElementById("anim");
anim.addEventListener("animationstart", AnimationListener, false);

动画第一次开始的时候触发animationstart事件。

2、animationiteration

anim.addEventListener("animationiteration", AnimationListener, false);

除了首次开始动画外,其它每次开始动画迭代都触发animationiteration事件。

3、animationend

anim.addEventListener("animationend", AnimationListener, false);

动画结束的时候触发animationend事件

浏览器的支持情况

W3c标准:animationstart animationiteration animationend

Webkit:webkitAnimationStart webkitAnimationIteration webkitAnimationEnd

Firefox:animationstart animationiteration animationend

Opera:animationstart animationiteration animationend

IE10:MSAnimationStart MSAnimationIteration MSAnimationEnd

下面是一段兼容性的监听css3动画的js代码:

var pfx = ["webkit", "moz", "MS", "o", ""];
function PrefixedEvent(element, type, callback) {
for (var p = 0; p < pfx.length; p++) {
if (!pfx[p]) type = type.toLowerCase();
element.addEventListener(pfx[p]+type, callback, false);
}
} // animation listener events
PrefixedEvent(anim, "AnimationStart", AnimationListener);
PrefixedEvent(anim, "AnimationIteration", AnimationListener);
PrefixedEvent(anim, "AnimationEnd", AnimationListener);

也可以用jquery提供的one方法来监听动画,如下面是动画结束的时候移除动画代码:

$('#anim').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(){
$(this).removeClass('enable');
});

事件对象

在上面的代码中,动画事件触发的时候将会调用动画监听函数。一个事件对象作为一个参数传递。在标准的属性和方法中,它还提供了:

animationName:css3动画的名称(如上面例子中的名称:flash)
elapsedTime:动画开始以来的执行事件(以秒为单位)

我们可以检测动画的结束,如:

if (e.animationName == "flash" && e.type.toLowerCase().indexOf("animationend") >= 0) {
...
}

代码中我们可以在动画执行结束后删除相应的class或应用新的动画等

但是如果我们想改变CSS animation(动画)执行过程中的动画,还需要一点技巧!

以下来自:http://css-tricks.com/controlling-css-animations-transitions-javascript/

animation-play-state属性

当你想在动画执行过程中暂停,并且接下来让动画接着执行。这时CSS的animation-play-state属性是非常有用的。你可以可以通过JavaScript像这样更改CSS(注意你的前缀):

element.style.webkitAnimationPlayState = "paused";
element.style.webkitAnimationPlayState = "running";

然而当使用animation-play-state让CSS 动画暂停时,动画中的元素变形也会以相同的方式被阻止。你不能使这种变形暂停在某个状态,使它变形,使它恢复,更不用期望它能从新的变形状态中恢复到流畅运行。为了实现这些控制,我们需要做一些更复杂的工作。

获取当前keyvalue的百分比

不幸的是,在这个阶段没有办法获得当前CSS动画关键帧的“完成百分比”。最好的获取近似值的方法是使用setInterval 函数在动画过程中迭代100次。它的本质是:动画持续的时间(单位是毫秒)/100。例如,如果动画时长4秒,则得到的setInterval的执行时间是每40毫秒(4000 / 100)。

这种做法很不理想,因为函数实际运行频率要远少于每40毫秒。我发现将它设为39毫秒更准确。但这个也不是好实现,因为它依赖于浏览器,并非所有浏览器下都能得到很完美效果。

获取当前动画的CSS属性值

你可以用document.styleSheets来获取与页面关联的样式表的集合,然后通过for循环取得具体的样式表。以下是如何使用JavaScript来找到一个特定动画值的CSSKeyFrameRules对象:

function findKeyframesRule(rule){
var ss = document.styleSheets;
for(var i = 0;i < ss.length;++i){
for(var j = 0;j<ss[i].cssRules.length;++j){
if(ss[i].cssRules[j].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE && ss[i].cssRules[j].name == rule){
return ss[i].cssRules[j];
}
}
}
return null;
}

我们一旦调用上面的函数(例如 var keyframes= findKeyframesRule(anim)),就可以通过keyframes.cssRules.length获得该对象的动画长度(这个动画中关键帧的总数量)。然后使用JavaScript的.map方法把获得到的每个关键帧值上的“%”过滤掉,这样JavaScript就可以把这些值作为数字使用。

// Makes an array of the current percent values
// in the animation
var keyframeString = [];
for(var i = 0; i < length; i ++){
keyframeString.push(keyframes[i].keyText);
}
// Removes all the % values from the array so
// the getClosest function can perform calculations
var keys = keyframeString.map(function(str) {
return str.replace('%', '');
});

这里keys是一个包含所有动画关键帧数值的数组。

改变实际的动画(终于!)

在循环动画演示过程中,我们需要两个变量:一个用来跟踪从最近的起始位置开始移动了多少度,另一个用来跟踪从原来的起始位置开始移动了多少度。我们可以使用setInterval函数(在环形移动度数时消耗的时间)改变第一个变量。然后我们可以使用下面的代码,当单击该按钮时更新第二个变量。

totalCurrentPercent += currentPercent;
// Since it's in percent it shouldn't ever be over 100
if (totalCurrentPercent > 100) {
totalCurrentPercent -= 100;
}

然后我们可以使用以下函数,在之前我们获得的关键帧数组里,找出与当前总百分比值最接近的关键帧值。

function getClosest(keyframe) {
// curr stands for current keyframe
var curr = keyframe[0];
var diff = Math.abs (totalCurrentPercent - curr);
for (var val = 0, j = keyframe.length; val < j; val++) {
var newdiff = Math.abs(totalCurrentPercent - keyframe[val]);
// If the difference between the current percent and the iterated
// keyframe is smaller, take the new difference and keyframe
if (newdiff < diff) {
diff = newdiff;
curr = keyframe[val];
}
}
return curr;
}

要获得新动画第一关键帧的位置值,我们可以使用JavaScript的.IndexOf方法。然后我们根据这个值,删除原来的关键帧定义,重新定义该关键帧。

for (var i = 0, j = keyframeString.length; i < j; i ++) {
keyframes.deleteRule(keyframeString[i]);
}

接下来,我们需要把圆的度数值转换成相应的百分比值。我们可以通过第一关键帧的位置值与3.6简单的相乘得到(因为10 0 * 3.6 = 360)。

最后,我们基于上面获得变量创建新的规则。每个规则之间有45度的差值,是因为我们在绕圈过程中拥有八个不同的关键帧,360(一个圆的度数)除以8是45。

// Prefix here as needed
keyframes.insertRule("0% {
-webkit-transform: translate(100px,100px) rotate(" + (multiplier + 0) + "deg)
translate(-100px,-100px) rotate(" + (multiplier + 0) + "deg);
background-color:red;
}");
keyframes.insertRule("13% {
-webkit-transform: translate(100px,100px) rotate(" + (multiplier + 45) + "deg)
translate(-100px,-100px) rotate(" + (multiplier + 45) + "deg);
}"); ...continued...

然后我们通过setInterval重置当前百分比值来使它可以再次运行。注意上面使用的是WebKit前缀,为了使它兼容更多的浏览器,我们需要做一些UA的嗅探来确定采用哪个前缀:

var browserPrefix;
navigator.sayswho= (function(){
var N = navigator.appName, ua = navigator.userAgent, tem;
var M = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
if(M && (tem = ua.match(/version\/([\.\d]+)/i))!= null) M[2] = tem[1];
M = M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
M = M[0];
if(M == "Chrome") { browserPrefix = "webkit"; }
if(M == "Firefox") { browserPrefix = "moz"; }
if(M == "Safari") { browserPrefix = "webkit"; }
if(M == "MSIE") { browserPrefix = "ms"; }
})();

如果你想进一步研究,可以访问Russell Uresti在StackOverflow上的帖子相应的案例

Animations(动画)转成Transitions(过渡)

正如我们所看到的,使用JavaScript可以很方便的操作CSS transitions(过渡)。如果使用CSS animations(动画)最终没能得到想要的结果,你可以试着把它变成css transitions(过渡)来实现。从CSS代码来看他们大约有相同的代码量,但使用transiton可以更容易地设置和编辑。

将CSS animations(动画)转换成CSS transitions(过渡)的最大问题是,当我们把animation-iteration转换成与之等效的transition命令时,Transitons(过渡)没有直接等效命令。

关于我们的旋转演示,有一个小技巧就是用x来分别乘以transition-duration和rotation(译者:分别包括X轴和Y轴的旋转值)。然后你需要使用样式类来触发这个动画,因为如果你在元素上直接改变这些属性,将不会有过渡效果。你需要给元素添加类名来触发过渡(模拟动画)。

在我们的例子中,我们在页面加载时实现:

执行效果:http://cdpn.io/IdlHx

利用CSS矩阵

你也通过CSSMatrix来操作CSS animations(动画)。比如:

var translated3D = new WebKitCSSMatrix(window.getComputedStyle(elem, null).webkitTransform);

但是这个过程可能有些混乱,尤其对于那些刚刚开始使用CSS animations(动画)的。

重置CSS animations(动画)

实现这个技巧的方法可以从CSS Tricks找到。

下面是几个例子:

http://jsfiddle.net/vals/BseLV/

http://jsfiddle.net/russelluresti/RHhBz/2/

CSS Transition中的事件

当CSS Transition完成时触发一个事件,在符合标准的浏览器下,这个事件是 transitionend, 在 WebKit 下是 webkitTransitionEnd,详见下面的浏览器兼容性。 transitionend 事件提供两个属性:

propertyName:字符串,指示已完成过渡的属性。
elapsedTime:浮点数,指示当触发这个事件时过渡已运行的时间(秒)。这个值不受 transition-delay 影响。

Note: 如果取消了过渡则不会触发 transitionend 事件,因为在过渡完成前动画的属性值改变了。

浏览器兼容性

Chrome:webkitTransitionEnd

Opera:10.5->oTransitionEnd,12->otransitionend,12.10->transitionend

Safari:webkitTransitionEnd

Android: webkitTransitionEnd

Opera Mobile:10->oTransitionEnd,12->otransitionend,12.10->transitionend

Safari Mobile:webkitTransitionEnd

本文链接:http://w3cboy.com/post/2014/03/如何使用js捕获css3动画/

发表于2014-03-25 12:53:53,并被添加「 css3 」标签,最后修改于2016-06-14 14:52:52

如何使用js捕获css3动画的更多相关文章

  1. 原生js判断css3动画过度(transition)结束 transitionend事件 以及关键帧keyframes动画结束(animation)回调函数 animationEnd 以及 css 过渡 transition无效

      上图的 demo 主要讲的 是 css transition的过渡回调函数transitionend事件: css3 的时代,css3--动画 一切皆有可能: 传统的js 可以通过回调函数判断动画 ...

  2. wow.js让css3动画变动更有趣(滚动页面动画模拟懒加载特效)

    CSS3的出现给网站页面增加了活力,网站增色不少,有这么小小的一款插件就能做出很多动画效果. 最重要的是它:简单易用.轻量级.无需 jQuery......他就是wow.js 地址:https://d ...

  3. JS模拟CSS3动画-贝塞尔曲线

    一.什么是贝塞尔曲线 1962年,法国工程师皮埃尔·贝塞尔(Pierre Bézier),贝塞尔曲线来为为解决汽车的主体的设计问题而发明了贝塞尔曲线.如今,贝赛尔曲线是计算机图形学中相当重要的一种曲线 ...

  4. js 模拟css3 动画3

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. js 模拟css3 动画1

    <html> <head> <title> javaScript缓动入门 </title> </head> <body> < ...

  6. js 模拟css3 动画

    <html> <head> <title> javaScript缓动入门 </title> </head> <body> < ...

  7. js 模拟css3 动画2

    <html> <head> <title> javaScript缓动入门 </title> </head> <body> < ...

  8. CSS3动画效果——js调用css动画属性并回调处理详解

    http://www.jb51.net/css/258407.html 这篇文章主要详细介绍了CSS3动画效果回调处理,需要的朋友可以参考下 我们在做js动画的时候,很多时候都需要做回调处理,如在一个 ...

  9. Bounce.js – 快速创建漂亮的 CSS3 动画效果

    Bounce.js 是一个用于制作漂亮的 CSS3 关键帧动画的 JavaScript 库,使用其特有的方式生成的动画效果.只需添加一个组件,选择预设,然后你就可以得到一个短网址或者导出为 CSS 代 ...

随机推荐

  1. CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

    1514: Packs Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 4[Submit][Status][Web Board] ...

  2. B. Pasha and String

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  3. 保持查询语法指示的联接顺序Option(Force order)

    Option(Force order) 今天和大家分享一下 SQL中强制执行联接顺序Option(Force Order) 一.SQL本身SQL引擎优化已经做的非常好了,但是也有默认的多表连接引擎效果 ...

  4. find 忽略文件夹选项-prune的说明

    注意:因为习惯在当前路径查找时候,常忽略./ 的指定,但读者不要因此而完全忘记find的格式. 查找时忽略指定目录,是要使用-prune选项,但实际上最重要的还是要和path配合.-prune的意义是 ...

  5. CSS选择器笔记

    一.元素选择符 序号 选择器 含义 1. * 通用元素选择器,匹配任何元素 2. E 标签选择器,匹配所有使用E标签的元素 3. .info class选择器,匹配所有class属性中包含info的元 ...

  6. centos 6.5 安装lnmp(linux+nginx+mysql+php)

    参考:http://www.cnblogs.com/AloneSword/archive/2013/03/18/2966750.html (总结并简要) 一安装cmake wget -c http:/ ...

  7. 关于HTML中浮动与清除的思考

    布局时需要利用浮动(float)的属性,同时我们需要一个清除浮动(clear)与之配合才能达到预期的目标. w3s上关于float和clear的定义分别为:float:float 属性定义元素在哪个方 ...

  8. Backbone.js学习之Collection

    首先,当然是一如既往地看官方文档的解释. Collections are ordered sets of models. 翻译: Collections是models的一个集合. 关于book和boo ...

  9. MongoDB - MongoDB CRUD Operations, Query Documents, Project Fields to Return from Query

    By default, queries in MongoDB return all fields in matching documents. To limit the amount of data ...

  10. DOS 批处理 修改xml文件

    之前对批处理和dos只停留在cd ping ipconfig水平,我以为改个文件应该很简单吧,把文件读出来做个替换再写回去不就欧了,百度个例子改改,那还不是分分钟的事,哪知道事实比想的要复杂的多. 我 ...