【问题标题】:Can I detect if an arbitrary CSS transition has started我可以检测任意 CSS 过渡是否已经开始
【发布时间】:2013-12-28 07:37:19
【问题描述】:

在我的关闭函数中,我想在 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 事件,我不知道如何检查转换是否已经开始。

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

【问题讨论】:

  • 如果您知道动画的属性是什么,您能否通过比较元素当前属性值与它的 css 样式值(又名目标)是什么来确定动画是否正在进行?
  • @milks 一般来说,我不知道正在转换什么,甚至根本不知道正在转换什么。 (实际上,最坏的情况甚至更棘手 - 我什至可能不知道过渡是否在外部元素上,例如在覆盖层中,内部内容区域可能会缩小到一个点,尽管外部覆盖层只是保持黑色......但这种情况是暂时不那么重要)
  • @RobM。不,不是。这个问题是关于过渡开始时的一个事件(不存在),那个问题是关于结束时的一个事件。
  • @CarloCannas 我明白了,感谢您指出这一点。

标签: javascript css events css-transitions


【解决方案1】:

关于 transitionStart 和 transitionEnd 事件:

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

在转换期间,用户 I/O 不会阻塞,因此转换是异步的,然后转换将结束,你不知道对不对。所以你需要 transitionEnd 事件来做一些事情,然后过渡在 javascript 中完成。

关于 transitionEnd 事件: 看看jsfiddle

【讨论】:

  • 我没有在我的js 代码中明确启动它。我在js 中添加了一个类,它在css 中应用了一些样式,这些样式可能涉及转换,所以我的js 不知道转换是否开始
  • 您可以通过Modernizr检查过渡支持(是否带前缀)。如果支持过渡,您可以检查 transitionDelaytransitionDurationtransitionProperty 的样式对象并获取值以了解过渡是否开始。
  • 您无法确定过渡何时开始,因为它是浏览器执行的异步操作,您不知道何时执行。看一看:stackoverflow.com/questions/27275872/…
【解决方案2】:

到目前为止,这是我的解决方案 - 有点老套,只有在知道哪个元素可能转换时才有效,并且不适用于 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);
}

【讨论】:

    【解决方案3】:

    没有办法(据我所知)在不知道正在转换的元素的情况下检测转换当前是否在后台工作。

    但是,如果您可以从过渡过渡到关键帧动画,那么您将拥有如此需要的事件 - animationStart 和 animationEnd,然后很容易确定是否有正在运行的动画。

    【讨论】:

      【解决方案4】:

      你试过 JQuery 伪“:animated”吗?

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

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

      【讨论】:

      【解决方案5】:

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

      非常强大和有用,你可以得到变换x值。例如 css('x')。

      【讨论】:

        【解决方案6】:

        这是一个等待页面 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;
            }));
        

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

            【解决方案8】:

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

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

            或者干脆做一个回调函数

            【讨论】:

              【解决方案9】:

              animation.css 我发现了这个。

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

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

              read full doc here

              【讨论】:

                猜你喜欢
                • 2014-01-26
                • 1970-01-01
                • 1970-01-01
                • 2014-08-08
                • 1970-01-01
                • 2011-09-09
                相关资源
                最近更新 更多