
上圖的 demo 主要講的 是 css transition的過渡回調函數transitionend事件;
css3 的時代,css3--動畫 一切皆有可能;
傳統的js 可以通過回調函數判斷動畫是否結束;即使是采用CSS技術生成動畫效果,JavaScript仍然能捕獲動畫或變換的結束事件;
transitionend事件和animationend事件標准的瀏覽器事件,但在WebKit瀏覽器里你仍然需要使用webkit前綴,所以,我們不得不根據各種瀏覽器分別檢測事件
var transitions = {
'transition':'transitionend',
'OTransition':'oTransitionEnd',
'MozTransition':'transitionend',
'WebkitTransition':'webkitTransitionEnd'
}
下面附上源代碼:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>suface js判斷css動畫是否結束</title>
</head>
<body>
<p>一旦動畫或變換結束,回調函數就會觸發。不再需要大型類庫支持。<br> </p>
<style type="text/css">
.sample {
width: 200px;
height: 200px;
border: 1px solid green;
background: lightgreen;
opacity: 1;
margin-bottom: 20px;
transition-property: opacity;
/*transition-duration: .5s;*/
transition-duration:3s;
}
.sample.hide {
opacity: 0;
}
</style>
<div class="sample">css3動畫過度慢慢隱藏(transition-duration:3s;)</div>
<p><button onclick="this.style.display='none';startFade();">慢慢消退,檢測結束事件</button></p>
<script>
;(function() {
var e = document.getElementsByClassName('sample')[0];
function whichTransitionEvent(){
var t,
el = document.createElement('surface'),
transitions = {
'transition':'transitionend',
'OTransition':'oTransitionEnd',
'MozTransition':'transitionend',
'WebkitTransition':'webkitTransitionEnd'
}
for(t in transitions){
if( el.style[t] !== undefined ){
return transitions[t];
}
}
}
var transitionEvent = whichTransitionEvent();
transitionEvent && e.addEventListener(transitionEvent, function() {
alert('css3運動結束!我是回調函數,沒有使用第三方類庫!');
e. removeEventListener(transitionEvent,arguments.callee,false);//銷毀事件
});
startFade = function() {
e.className+= ' hide';
}
})();
</script>
</body>
</html>
//兼容性 詳情

另外,注意一下:在js調用中;transitionend 存幾個個問題:
如果 transition 中:變換的屬性有多個 ;比如設置寬高 過度(transition :width:.2s,height:.2s), transitionend 事件會促發2次
<style>
.surfaces_box{ background:url(../../loveImg/QioA-fxehfqi8208393.jpg) no-repeat center center;;width:550px;;height:343px;; margin:0 auto; position: relative;}
.surfaces_box p{ position:absolute; bottom:0; left:0; right:0; color:#333; text-align:center; padding:10px 0; background: rgba(255,255,255,.4) }
.surfaces{width:100px;height:100px;background:red; color:#fff; text-align:center; transition:width 1s ,height 1s;}
</style>
<div class="surfaces_box">
<div class="surfaces" id="j_surfaces">click me </div>
<p>http://www.cnblogs.com/surfaces/</p>
</div>
<script>
function addEnd(obj,fn){
obj.addEventListener('WebkitTransitionEnd',fn,false);
obj.addEventListener('transitionend',fn,false);
}
var surfaces=document.getElementById("j_surfaces");
surfaces.onclick=function(){
this.style.width=this.offsetWidth+100+"px";
this.style.height=this.offsetHeight+100+"px";
};
addEnd(surfaces,function(){
alert('CSS3 過渡結束回調 ');
});
</script>
如果 transition 中:變換的屬性 (transition :width:.1s);transitionend 之后再次改變 寬度; 再次促發 transition類似遞歸;

<style>
.surfaces_box{ background:url(../../loveImg/QioA-fxehfqi8208393.jpg) no-repeat center center;;width:550px;;height:343px;; margin:0 auto; position: relative;}
.surfaces_box p{ position:absolute; bottom:0; left:0; right:0; color:#333; text-align:center; padding:10px 0; background: rgba(255,255,255,.4) }
.surfaces{width:100px;height:100px;background:red; color:#fff; text-align:center; transition:width 1s}
</style>
<div class="surfaces_box">
<div class="surfaces" id="j_surfaces">click me </div>
<p>http://www.cnblogs.com/surfaces/</p>
</div>
<script>
function addEnd(obj,fn){
obj.addEventListener('WebkitTransitionEnd',fn,false);
obj.addEventListener('transitionend',fn,false);
}
var surfaces=document.getElementById("j_surfaces");
surfaces.onclick=function(){
this.style.width=this.offsetWidth+100+"px";
};
addEnd(surfaces,function(){
this.style.width=this.offsetWidth+100+"px";
alert('CSS3 過渡結束回調 ');
});
</script>
如果元素原先display:none 到block,transition 過渡無效;可能導致transitionend 失效;舉個例子 dom元素從display:none 到block ,dom的opacity從0到1的 transition沒過渡 ;

<style>
.surfaces_box{ background:url(../../loveImg/QioA-fxehfqi8208393.jpg) no-repeat center center;;width:550px;;height:343px;; margin:0 auto; position: relative;}
.surfaces_box p{ position:absolute; bottom:0; left:0; right:0; color:#333; text-align:center; padding:10px 0; background: rgba(255,255,255,.4) }
.surfaces{width:100px;height:100px;background:red; color:#fff; text-align:center; transition:width 1s}
.surfaces_box .hideElement{width:100px;height:100px; position:absolute; right:0; top:0; background:red; color:#fff; text-align:center; transition:opacity 1s; display:none; opacity:0;}
</style>
<div class="surfaces_box">
<div class="surfaces" id="j_surfaces">click me </div>
<div class="hideElement" id="j_hideElement">opacity transition</div>
<p>http://www.cnblogs.com/surfaces/</p>
</div>
<script>
var j_hideElement=document.getElementById("j_hideElement");
var surfaces=document.getElementById("j_surfaces");
surfaces.onclick=function(){
j_hideElement.style.display='block'; //// 原先display=none
j_hideElement.style.opacity=1; // transition:opacity 1s;
};
</script>
上圖 dom元素 從none到block,導致 transition-duration 無法渲染;
1 一般是這樣解決 加個計時器延遲


2 或者 強制 /強制 獲取當前的內聯樣式

3或者重繪

都是從none到block ,dom元素剛生成未能即使渲染,導致過度失效,所以主動觸發頁面回流(重繪),刷新DOM;
更改 offsetTop、offsetLeft、 offsetWidth、offsetHeight;scrollTop、scrollLeft、scrollWidth、scrollHeight;clientTop、clientLeft、clientWidth、clientHeight;getComputedStyle() 、currentStyle()。這些都會觸發回流。回流導致DOM重新渲染,平時要盡可能避免,但這里,為了動畫即時生效播放,則主動觸發回流,刷新DOM。
4 另外 部分低端安卓機型或者wp手機 無法促發 transitionend事件 需要主動觸發一次
以上綜合解決方式大致如下;
var fired = false;
var handler = function () {//回調函數中解綁事件
callback && callback.apply(obj,arguments);
fired=true;
obj.removeEventListener(transitionEnd,arguments.callee,false)
};
if(obj.addEventListener){
obj.addEventListener(transitionEnd, handler,false);
}
setTimeout(function(){//綁定過事件還做延時處理,是transitionEnd在older Android phones不一定觸發
if(fired) return
handler()
},(duration + delay) + 25);
我們進行封裝一下;封裝后的直接調用如下;參考zepto 改寫;不依賴任何類庫,詳情源碼調用例子 點擊transform.js 查看;該函數兼容性與zepto一致;
transform(dom元素,{ css屬性:css值},transitionDuration(單位:毫秒),transitionTiming,transitionend回調函數,transitionDelay(單位:毫秒));
transform(dom元素,keyframesName,animationDuration,animationTiming,animationend回調函數,animationDelay(單位:毫秒));
參數說明:
/* * js transfrom.js * @param obj {obj} 原生dom對象 * @param properties {json} ||string { translate3d:'220px,10px,0',left:'1em',opacity:0.2, rotateY:'30deg'} || animationName 多個可以以逗號分割 如 'fadeIn,sliderDown'; * @param duration {number} 默認400毫秒 可省略 * @param ease {str} 默認linear,可省略 支持 cubic-bezier(0.42,0,1,1)寫法; * @param callback {function} 回調函數 可省略 * @param delay {number} 延遲時間 可省略 */
多種參數 調用寫法示例:
/* http://www.cnblogs.com/surfaces * @param properties 為 {} 或者 string ;如果 properties= string 為animation- name * transform(elem, properties) * transform(elem, properties, ease) * transform(elem, properties, ease, delay) * transform(elem, properties, ease, callback, delay) * transform(elem, properties, callback) * transform(elem, properties, callback, delay) * transform(elem, properties, duration ) * transform(elem, properties, duration, ease) * transform(elem, properties, duration, delay) * transform(elem, properties, duration, callback) * transform(elem, properties, duration, callback,delay) * transform(elem, properties, duration, ease, delay) * transform(elem, properties, duration, ease, callback) * transform(elem, properties, duration, ease, callback,delay) //使用示例如下: transform(elem,{translateX:'150px',left:'1em',opacity:0.2,perspective:'400px', rotateY:'40deg'},600,'linear', function(){ console.log('transition結束回調') },200) ; transform(elem, keyframesName,600,'linear',function(){ console.log('animation結束回調') },200) ; */
不要搞混css3動畫事件 webkitAnimationEnd 事件
至於animation關鍵幀動畫結束,提供了3個api;如下
開始事件 webkitAnimationStart
結束事件 webkitAnimationEnd
重復運動事件 webkitAnimationIteration;

本文地址:http://www.cnblogs.com/surfaces/
總結:
相同點:
兩者都在移動端大放光彩;利用GPU加速性能,相對流暢;
利用 js進行對動畫結束事件可以捕捉監聽;
區別之處
transition 只有唯一的事件 transitionend,而animation 有3個;
transition 強調過渡,Transition + Transform = 兩個關鍵幀的Animation
animation 強調流程與控制,Duration + TransformLib + Control = 多個關鍵幀的Animation
animation 可以實時捕捉操作修改屬性, 而transition無法捕捉 中間過程;
transition 往往需要事件驅動,hover,click之類 促發,animation從flash延伸出來
