如何使用jQuery来等待CSS3转换的结束



我想淡出一个元素(将其不透明度转换为0),然后在完成后从DOM中删除该元素。

在jQuery中,这是直接的,因为您可以指定在动画完成后进行"移除"。但是,如果我想使用CSS3过渡制作动画,是否可以知道过渡/动画何时完成?

对于转换,您可以使用以下内容通过jQuery检测转换的结束:

$("#someSelector").bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){ ... });

Mozilla有一个很好的参考:

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#Detecting_the_start_and_completion_of_a_transition

对于动画来说,它非常相似:

$("#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);
 });

参考文献:

  • .off()

  • .one()

可以观察到一个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(); });
});

JS Fiddle演示

对于任何对此可能很方便的人来说,这里有一个依赖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这样的动画库。

接受的答案当前为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的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')
));

如果你不想使用箭头函数,你必须像这样传递event+元素:

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(//[...]

相关内容

  • 没有找到相关文章

最新更新