我可以检测是否已开始任意CSS转换

时间:2013-12-10 16:51:33

标签: javascript css css3 events css-transitions

在我的关闭函数中,我希望在css转换完成运行后执行所有DOM清理工作。但可能没有任何转换正在运行/可能是多阶段转换 - (维护样式表不在我的手中)。

我如何编写类似于以下内容的函数

function close () {
  myEl.removeClass('open');
  if (animation is running/about to be run) {
    // wait for transition to end, then recursively check to see if another 
    // one has started, wait for that ...
    // then
    cleanUpDOM(); 
  } else {
    cleanUpDOM(); 
  }
}

到目前为止,我的想法是将初始检查包装在timeout / requestAnimationFrame中,以便为动画提供启动机会,然后检查它是否正在运行。不幸的是,如果没有transitionstart事件,我不知道如何检查转换是否已经开始。

编辑推荐jquery的答案是无关紧要的,因为jquery动画是javascript动画,而不是CSS过渡

9 个答案:

答案 0 :(得分:1)

关于transitionStart和transitionEnd事件:

过渡不能从无处开始。通常,转换在某个事件之后开始,您可以通过按类或其他方式更改样式来更改DOM元素的状态。所以你知道什么时候开始转换因为你在代码中启动它。

在转换期间,用户I / O不会阻塞,因此转换是异步的,然后转换将结束您不知道的权利。因此,您需要transitionEnd事件来执行某些操作,然后在javascript中完成转换。

关于transitionEnd事件: 只需查看jsfiddle

即可

答案 1 :(得分:1)

到目前为止,这是我的解决方案 - 有点hacky,只有当哪个元素可能转换时才有效,并且不适用于transition-property: all ...但这是一个很有希望的开始

function toCamelStyleProp (str) {
    return str.replace(/(?:\-)([a-z])/gi, function ($0, $1) {
        return $1.toUpperCase();
    });
}

function toHyphenatedStyleProp (str) {
    return str.replace(/([A-Z])/g, function (str,m1) {
        return '-' + m1.toLowerCase();
    }).replace(/^ms-/,'-ms-');
}

function getPrefixedStyleProp (prop) {
    prop = toCamelStyleProp(prop);
    prop = Modernizr.prefixed(prop);
    return toHyphenatedStyleProp(prop);
}

function getStyleProperty (el, prop) {
    return getComputedStyle(el,null).getPropertyValue(getPrefixedStyleProp(prop));
}

function doAfterTransition ($wrapper, cssClass, mode, $transitioningEl, callback) {
    $transitioningEl = $transitioningEl || $wrapper;

    var transitioningEl = $transitioningEl[0],
        duration = +getStyleProperty(transitioningEl, 'transition-duration').replace(/[^\.\d]/g, ''),
        transitioners = getStyleProperty(transitioningEl, 'transition-property').split(' '),
        initialState = [],
        changedState = [],
        i,
        callbackHasRun = false,

        //makes sure callback doesn't get called twice by accident
        singletonCallback = function () {
            if (!callbackHasRun) {
                callbackHasRun = true;
                callback();
            }
        };

    // if no transition defined just call the callback
    if (duration === 0) {
        $wrapper[mode + 'Class'](cssClass);
        callback();
        return;
    }

    for (i = transitioners.length - 1;i>=0;i--) {
        initialState.unshift(getStyleProperty(transitioningEl, transitioners[i]));
    }

    $wrapper[mode + 'Class'](cssClass);

    setTimeout(function () {
        for (i = transitioners.length - 1;i>=0;i--) {
            changedState.unshift(getStyleProperty(transitioningEl, transitioners[i]));
        }

        for (i = transitioners.length - 1;i>=0;i--) {
            if (changedState[i] !== initialState[i]) {
                $transitioningEl.transitionEnd(singletonCallback);

                // failsafe in case the transitionEnd event doesn't fire
                setTimeout(singletonCallback, duration * 1000);
                return;
            }
        }
        singletonCallback();
    }, 20);
}

答案 2 :(得分:1)

我无法(我知道)在不知道正在转换的元素的情况下检测转换当前是否在后台运行。

但是,如果您可以从过渡到关键帧动画,那么您就拥有了所需的事件 - animationStart和animationEnd,然后很容易弄清楚是否有正在运行的动画。

答案 3 :(得分:1)

您是否尝试过JQuery伪“:动画”?

if($(element).is(':animated')){...}

查看更多 http://api.jquery.com/animated-selector/

答案 4 :(得分:0)

如果您打算进行css转换,可以查看jQuery Transit Plugin http://ricostacruz.com/jquery.transit/

非常强大且有用,你可以获得转换x值。例如,css('x')。

答案 5 :(得分:0)

这是一个等待页面Html变得稳定的函数。即所有动画完成时。在下面的示例中,它等待Html不变为200毫秒,最大超时为2秒。

使用...

调用该函数
waitUntilHtmlStable(yourCallback, 200, 2000);

功能......

waitUntilHtmlStable = function (callback, unchangedDuration, timeout, unchangedElapsed, html) {
    var sleep = 50;
    window.setTimeout(function () {
        var newHtml = document.documentElement.innerHTML;
        if (html != newHtml) unchangedElapsed = 0;
        if (unchangedElapsed < unchangedDuration && timeout > 0)
            waitUntilHtmlStable(callback, unchangedDuration, timeout - interval, unchangedElapsed + interval, newHtml);
        else
            callback();
    }, sleep);
};

在我的情况下,我想确定存在的新元素。如果要跟踪动画移动,请将document.documentElement.innerHTML更改为

JSON.stringify(Array.prototype.slice.call(document.documentElement.getElementsByTagName("*"), 0)
.map(function(e) {
        var x = e;
        var r = x.getBoundingClientRect();
        while (r.width == 0 || r.height == 0) {
            x = x.parentNode;
            r = x.getBoundingClientRect();
        }
        return r;
    }));

答案 6 :(得分:0)

IE10 +中有一个无前缀的transitionstart事件。它甚至可以取消。

https://msdn.microsoft.com/library/dn632683%28v=vs.85%29.aspx

答案 7 :(得分:-1)

animation.css我找到了这个。

您还可以检测动画何时结束:

$('#yourElement').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', doSomething);

read full doc here

答案 8 :(得分:-1)

你可以使用Jquery,这可以更容易,例如你可以像这样使用.animate

(function(){
            var box = $('div.box')
            $('button').on('click', function(){
                box.animate({ 'font-size' : '40px'})
                .animate({'color': 'red'});
            })
        })();

或只是做一个回调函数