过渡结束/动画结束事件的特征检测?

6
我希望找到一种更简洁的方式来检测实际的transitionend名称。我看过很多例子,都是强制添加处理程序来应对各种变化。而且,我不想依赖于jQuery(或类似的框架)。
我基本上是从这个列表开始,并希望只绑定最佳匹配项(即,与列表中第一个匹配的项)。
var transitionendName,
    events = [
        'transitionend',
        'webkitTransitionEnd',
        'MozTransitionEnd',
        'oTransitionEnd'
    ];

// ^^^^^ your code here

myElem.addEventListener(transitionendName, myHandler, false);

有没有人觉得他们对此有一个干净的解决方案?同样的解决方案可能适用于“animationend”事件。

编辑: msTransitionEnd和以“-ms-”为前缀的属性在IE10的最终版本候选中被删除

4个回答

4

另一种变体适合于纯特性检测(而不是纯实用解决方案),但效率更高:

var transitionendNames = [
    'transitionend',
    'webkitTransitionEnd',
    'MozTransitionEnd',
    'oTransitionEnd'
];

/**
 * Helper function to bind to the correct transitionend event
 * @param {function} callback The function to call when the event fires
 */
var transitionend = function(elem, callback) {
    var handler = function(e) {
        //console.log('transitionend == '+e.type);

        // test in case multiple were registered before change
        if (transitionendNames) {
            // store the actual name
            var transitionendName = e.type;

            // every other time, bind only to actual event
            transitionend = function(elem, callback) {
                elem.addEventListener(transitionendName, callback, false);
            };

            // flag for any others
            transitionendNames = null;
        }
        return callback.call(elem, e);
    };

    // until an event has been triggered bind them all
    for (var i=0, len=transitionendNames.length; i<len; i++) {
        elem.addEventListener(transitionendNames[i], handler, false);
    }
};

我会给你点赞,即使我有一个竞争性的答案。我得出结论说整个问题没有感兴趣的读者,而且 OP 也没有太多关注。 - jfriend00
2
不好意思,我没意识到你是原帖发布者。原帖发布者提供多个答案并不常见,事实上我以前从没见过。我以为你只是另一个回答者而已。看起来只有你和我在花时间回答这个问题了。 - jfriend00
2
好的,无论如何感谢您讨论可能的解决方案所提供的帮助。 - mckamey
@jfriend00 - 我也经常回答自己的问题,我为什么不呢?如果我知道如何做某事,那么我会在这里提出问题并回答自己,这样就会有在线文档,其他人可以学习。 - vsync
记得移除未使用的事件监听器,以避免内存泄漏。 - arve0
显示剩余3条评论

4
你可以注册所有事件结束名称,然后触发一个非常短的CSS过渡,并查看哪个会触发。此外,IE10使用transitionend,所以没有浏览器使用msTransitionEnd
以下是如何执行的示例:http://jsfiddle.net/jfriend00/5Zv9m/
var transitionendName,
    events = [
        'transitionend',
        'webkitTransitionEnd',
        'MozTransitionEnd',
        'oTransitionEnd'
    ];

function findTransitionEnd(callback) {
    // add an off-screen element
    var elem = document.createElement("div");
    elem.id = "featureTester";
    document.body.appendChild(elem);

    // clean up temporary element when done
    function cleanup() {
        document.body.removeChild(elem);
        elem = null;
    }

    // set fallback timer in case transition doesn't trigger
    var timer = setTimeout(function() {
        if (!transitionendName) {
            cleanup();
            callback("");
        }
    }, 200);

    // register all transition end names
    for (var i = 0; i < events.length; i++) {
        (function(tname) {
            elem.addEventListener(tname, function() {
                if (!transitionendName) {
                    transitionendName = tname;
                    clearTimeout(timer);
                    cleanup();
                    callback(tname);
                }

            });
        })(events[i]);
    }


    // trigger transition
    setTimeout(function() {
        elem.className = "featureTestTransition";
    }, 1);
}

我可能会继续使用暴力算法来进行第一次尝试,然后记录返回结果以供将来迭代使用。仅仅为了检测特定的功能而显式触发似乎有些不好。 - mckamey
@McKAMEY - 我不确定为什么你觉得这很不好。特性检测的全部意义在于设置一个情境并通过编程方式检查浏览器的响应。这就是这里正在做的事情。 - jfriend00
是的,但它很重且时间敏感。这种类型的事情经过一段时间后会真正累积起来。当需要检查功能的大量这些测试时,会延迟页面加载。 - mckamey
@McKAMEY - 这是异步的,所以我怀疑它不会以任何方式减慢页面加载速度。如果您想在结束事件名称上进行特性检测,您必须运行一个转换并查看哪个事件名称有效。如果您只想查看存在哪些样式属性,然后假设您知道哪个结束事件名称与该样式属性相对应,您当然可以这样做,但我认为这不是您所问的。 - jfriend00

3

我知道这篇文章有些老了,但我想补充一下:style属性并不总是检测animationend/transitionend前缀的好方法。例如,一些Android浏览器在过渡效果中不使用前缀,但在JS事件中使用webkitAnimationEnd。


1
我敢说,样式属性绝不是检测事件是否有前缀的好方法。截至今天,被接受的答案在iPad/Safari上至少已经失效了。 - Brandon Gano

0

使用 @jfriend00 的答案/示例,创建轻量级检测变得更加容易。

// cssPrefix is any method which detects the property name
var transition = cssPrefix('transition');

var transitionend = {
    'transition': 'transitionend',
    'webkitTransition': 'webkitTransitionEnd',
    'MozTransition': 'transitionend',
    'OTransition': 'oTransitionEnd'
}[transition];

在实际应用中查看:http://jsfiddle.net/mckamey/qWPTg/

1
这实际上并没有对“transistionend”事件进行功能测试,这正是我认为OP所要求的。它寻找一个样式属性,然后假设特定的过渡结束事件名称与该样式名称相对应。 - jfriend00
此功能检测样式属性(可高效执行),并使用相应的 transitionend 事件名称。 - mckamey
所有这些都假定他们知道所有供应商前缀,因此需要一些先验知识。 - mckamey
我刚在其他地方看到了一个类似的想法:https://github.com/dmotz/oriDomi/blob/master/oriDomi.js#L80 - mckamey
大家需要小心那些switch语句,因为IE 10不使用MS前缀来表示CSS3,而是使用标准名称而没有前缀。 - jfriend00
那个开关分支将会处于休眠状态。它不会有任何影响,从技术上讲,它仍然可以覆盖使用这些前缀的IE10预览版本。 - mckamey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接