我想淡出一个元素(将其不透明度过渡到0),然后当完成后从DOM中删除该元素。
在jQuery中,这很简单,因为您可以指定“删除”在动画完成后发生。但是,如果我希望使用CSS3过渡进行动画处理,有没有办法知道过渡/动画何时完成?
我希望能够为您提供帮助!我想淡出一个元素(将其不透明度过渡到0),然后当完成后从DOM中删除该元素。
在jQuery中,这很简单,因为您可以指定“删除”在动画完成后发生。但是,如果我希望使用CSS3过渡进行动画处理,有没有办法知道过渡/动画何时完成?
我希望能够为您提供帮助!您可以使用以下方式通过jQuery检测转换结束的情况:
$("#someSelector").bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){ ... });
Mozilla提供了一份绝佳的参考资料:
对于动画,这也非常类似:
$("#someSelector").bind("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd", function(){ ... });
请注意,您可以同时将所有带有浏览器前缀的事件字符串传递到bind()方法中,以支持在支持它的所有浏览器上触发事件。
更新:
根据Duck留下的评论:您可以使用jQuery的.one()
方法确保处理程序仅触发一次。例如:
$("#someSelector").one("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){ ... });
$("#someSelector").one("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd", function(){ ... });
更新2:
jQuery bind()
方法已被弃用,jQuery 1.7
版本之后推荐使用on()
方法。bind()
你也可以在回调函数上使用off()
方法,以确保它只会被触发一次。以下示例与使用one()
方法等价:
$("#someSelector")
.on("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd",
function(e){
// do something here
$(this).off(e);
});
参考资料:
.on()
而不是 .bind()
。http://api.jquery.com/bind/ - olo有一个可以被观察到的animationend
事件,请参阅文档此处,同时对于css transition
动画,您可以使用 transitionend
事件。
这些都可以在原生JS中使用,无需额外的库。
document.getElementById("myDIV").addEventListener("transitionend", myEndFunction);
function myEndFunction() {
this.innerHTML = "transition event ended";
}
#myDIV {transition: top 2s; position: relative; top: 0;}
div {background: #ede;cursor: pointer;padding: 20px;}
<div id="myDIV" onclick="this.style.top = '55px';">Click me to start animation.</div>
另一种选择是使用jQuery Transit Framework来处理CSS3转换。 这些转换/效果在移动设备上表现良好,您无需在CSS文件中添加混乱的CSS3转换代码即可实现动画效果。
以下是一个示例,当您单击它时,将把元素的不透明度过渡到0,并在过渡完成后将其删除:
$("#element").click( function () {
$('#element').transition({ opacity: 0 }, function () { $(this).remove(); });
});
如果有人需要,这里提供一个依赖于jQuery的函数,可以通过应用CSS类来实现CSS动画,并在之后获取回调。它可能不完美,因为我是在Backbone.js应用程序中使用它的,但可能很有用。
var cssAnimate = function(cssClass, callback) {
var self = this;
// Checks if correct animation has ended
var setAnimationListener = function() {
self.one(
"webkitAnimationEnd oanimationend msAnimationEnd animationend",
function(e) {
if(
e.originalEvent.animationName == cssClass &&
e.target === e.currentTarget
) {
callback();
} else {
setAnimationListener();
}
}
);
}
self.addClass(cssClass);
setAnimationListener();
}
cssAnimate.call($("#something"), "fadeIn", function() {
console.log("Animation is complete");
// Remove animation class name?
});
原始想法来自 http://mikefowler.me/2013/11/18/page-transitions-in-backbone/
这个看起来很方便: http://api.jqueryui.com/addClass/
更新
在与上述代码和其他选项的斗争中,我建议非常谨慎地监听CSS动画结束。随着多个动画的进行,事件监听可能会变得非常混乱。我强烈建议使用动画库,例如GSAP,即使是小的动画。
e.stopImmediatePropagation(); self.trigger(this.whichAnimationEvent()); //用于清除现有事件 callback.apply(self);
- BomAlewebkitAnimationEnd
和animationEnd
。下面的代码一定只会触发一次:/* From Modernizr */
function whichTransitionEvent(){
var el = document.createElement('fakeelement');
var transitions = {
'animation':'animationend',
'OAnimation':'oAnimationEnd',
'MSAnimation':'MSAnimationEnd',
'WebkitAnimation':'webkitAnimationEnd'
};
for(var t in transitions){
if( transitions.hasOwnProperty(t) && el.style[t] !== undefined ){
return transitions[t];
}
}
}
$("#elementToListenTo")
.on(whichTransitionEvent(),
function(e){
console.log('Transition complete! This is the callback!');
$(this).off(e);
});
使用 Promises 实现可链式的单向事件
如果你需要像 JQuery 的 one()
一样的单向事件,我发现这种模式非常方便:
function awaitTransitionEnd(transitionProperty, el, triggerFunction) {
return new Promise((resolve, reject) => {
const handler = (e) => {
if (e.propertyName !== transitionProperty) {
return;
}
el.removeEventListener('transitionend', handler);
resolve(e);
}
el.addEventListener('transitionend', handler);
triggerFunction(el);
});
}
你可以像这个例子一样链接CSS过渡效果:
awaitTransitionEnd(
'background-color', myEl, () => myEl.classList.replace('bg-red', 'bg-green')
).then(() => awaitTransitionEnd(
'opacity', myEl, () => myEl.classList.add('opacity-0')
)).then(() => awaitTransitionEnd(
'opacity', myEl, () => myEl.classList.remove('opacity-0')
));
如果您不想使用箭头函数,您必须像这样传递事件+元素:
awaitTransitionEnd('background-color', myEl, function(el) {
el.classList.replace('bg-red', 'bg-green');
}).then(function(e) {
return awaitTransitionEnd('opacity', e.target, function(el) {
el.classList.add('opacity-0');
});
}).then(function(e) {
return awaitTransitionEnd('opacity', e.target, function(el) {
el.classList.remove('opacity-0');
});
});
当 awaitTransitionEnd
是一个类方法且您不想使用箭头函数时,您必须将 this
绑定到每个 then()
闭包上:
//[...]
.then(function(e) {
return this.awaitTransitionEnd('opacity', e.target, function(el) {
el.classList.add('opacity-0');
});
}.bind(this)).then(//[...]