【发布时间】:2012-03-04 13:05:31
【问题描述】:
我想淡出一个元素(将其不透明度转换为 0),然后在完成后从 DOM 中删除该元素。
在 jQuery 中这是直截了当的,因为您可以指定“删除”在动画完成后发生。但是,如果我想使用 CSS3 过渡制作动画,是否知道过渡/动画何时完成?
【问题讨论】:
标签: javascript jquery css css-transitions
我想淡出一个元素(将其不透明度转换为 0),然后在完成后从 DOM 中删除该元素。
在 jQuery 中这是直截了当的,因为您可以指定“删除”在动画完成后发生。但是,如果我想使用 CSS3 过渡制作动画,是否知道过渡/动画何时完成?
【问题讨论】:
标签: javascript jquery css css-transitions
带有承诺的可链式单向事件
如果您需要像 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()-closure:
//[...]
.then(function(e) {
return this.awaitTransitionEnd('opacity', e.target, function(el) {
el.classList.add('opacity-0');
});
}.bind(this)).then(//[...]
【讨论】:
有一个animationend 可以观察到的事件,请参阅文档here,
对于 css transition 动画,您也可以使用 transitionend 事件
不需要额外的库,这些都可以与 vanilla 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 检测过渡的结束:
$("#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() 方法已被弃用,on() 方法自jQuery 1.7 起是首选方法。 bind()
您也可以在回调函数上使用off() 方法来确保它只会被触发一次。这是一个等效于使用one() 方法的示例:
$("#someSelector")
.on("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd",
function(e){
// do something here
$(this).off(e);
});
参考资料:
【讨论】:
.on() 而不是 .bind() api.jquery.com/bind
Chrome 中的动画当前会触发两次已接受的答案。这大概是因为它可以识别webkitAnimationEnd 以及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);
});
【讨论】:
对于任何这可能很方便的人,这里有一个依赖 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()); //for purge existing event callback.apply(self);
另一种选择是使用 jQuery Transit Framework 来处理您的 CSS3 过渡。过渡/效果在移动设备上表现良好,您不必在 CSS 文件中添加一行凌乱的 CSS3 过渡来制作动画效果。
下面是一个示例,当您单击一个元素时,它会将其不透明度转换为 0,并在转换完成后将其移除:
$("#element").click( function () {
$('#element').transition({ opacity: 0 }, function () { $(this).remove(); });
});
【讨论】: