如何规范跨浏览器的 CSS3 过渡结束事件?

Posted

技术标签:

【中文标题】如何规范跨浏览器的 CSS3 过渡结束事件?【英文标题】:How do I normalize the CSS3 transition end events across browsers? 【发布时间】:2011-06-28 18:05:29 【问题描述】:

Webkit的transition结束事件叫webkitTransitionEnd,Firefox是transitionEnd,opera是oTransitionEnd。在纯 JS 中解决所有这些问题的好方法是什么?我应该做浏览器嗅探吗?还是分别实施每一项?我还没有想到其他方法?

即:

//doing browser sniffing
var transitionend = (isSafari) ? "webkitTransitionEnd" : (isFirefox) ? "transitionEnd" : (isOpera) ? "oTransitionEnd";

element.addEventListener(transitionend, function()
  //do whatever
,false);

// Assigning an event listener per browser
element.addEventListener("webkitTransitionEnd", fn);
element.addEventListener("oTransitionEnd", fn);
element.addEventListener("transitionEnd", fn);

function fn() 
   //do whatever

【问题讨论】:

假的目的是什么? 【参考方案1】:

第二个是要走的路。在每个浏览器中只会触发其中一个事件,因此您可以设置所有这些事件,它会起作用。

【讨论】:

【参考方案2】:

我使用这样的代码(使用 jQuery)

var vP = "";
var transitionEnd = "transitionend";
if ($.browser.webkit) 
    vP = "-webkit-";
    transitionEnd = "webkitTransitionEnd";
 else if ($.browser.msie) 
    vP = "-ms-";
 else if ($.browser.mozilla) 
    vP = "-moz-";
 else if ($.browser.opera) 
    vP = "-o-";
    transitionEnd = "otransitionend"; //oTransitionEnd for very old Opera

这让我可以使用 JS 通过指定与属性连接的 vP 来添加内容,如果它没有访问浏览器,它只是使用标准。这些事件让我可以像这样轻松地绑定:

object.bind(transitionEnd,function()
    callback();
);

【讨论】:

谢谢!我最终做了类似的事情,但没有浏览器嗅探。您可以在此处查看结果(和代码):cssglue.com/cubic。您的解决方案的唯一问题是——如果浏览器供应商决定标准化他们的转换事件——他们可能会放弃他们的前缀并且他们会停止工作(不太可能)。但是,是的,它使代码更加简洁。 我同意,我一直想用更好的东西代替我的,但另一方面我喜欢它的简单性。 物有所值。只需执行object.bind('transitionend oTransitionEnd webkitTransitionEnd', function() // callback );,无需浏览器嗅探即可完成此操作 事件的无前缀版本被命名为transitionend,而不是TransitionEnd【参考方案3】:

根据 Matijs 的评论,检测转换事件的最简单方法是使用库,在本例中为 jquery:

$("div").bind("webkitTransitionEnd.done oTransitionEnd.done otransitionend.done transitionend.done msTransitionEnd.done", function()
  // Unlisten called events by namespace,
  // to prevent multiple event calls. (See comment)
  // By the way, .done can be anything you like ;)
  $(this).off('.done')
);

在无库的 javascript 中,它变得有点冗长:

element.addEventListener('webkitTransitionEnd', callfunction, false);
element.addEventListener('oTransitionEnd', callfunction, false);
element.addEventListener('transitionend', callfunction, false);
element.addEventListener('msTransitionEnd', callfunction, false);

function callfunction() 
   //do whatever

【讨论】:

倒数第二个不应该是驼峰式。 很有趣,我来这里是因为我的同事刚刚发现他们的代码中抛出了多个事件,看起来与这个答案一模一样 @Duopixel 请测试您的答案并考虑更改它,因为它会在 Chrome 和 Safari(以及至少所有其他 Webkit 浏览器以及旧的 firefox 和 opera)中引发两个事件。 msTransitionend 这里不需要。 如果您转换了多个属性,它将触发多个事件。见:***.com/a/18689069/740836【参考方案4】:

Modernizr 中使用了一种技术,经过改进:

function transitionEndEventName () 
    var i,
        undefined,
        el = document.createElement('div'),
        transitions = 
            'transition':'transitionend',
            'OTransition':'otransitionend',  // oTransitionEnd in very old Opera
            'MozTransition':'transitionend',
            'WebkitTransition':'webkitTransitionEnd'
        ;

    for (i in transitions) 
        if (transitions.hasOwnProperty(i) && el.style[i] !== undefined) 
            return transitions[i];
        
    

    //TODO: throw 'TransitionEnd event is not supported in this browser'; 

然后您可以在需要转换结束事件时调用此函数:

var transitionEnd = transitionEndEventName();
element.addEventListener(transitionEnd, theFunctionToInvoke, false);

【讨论】:

oTransitionEnd 在 Opera 中小写为 otransitionend。见opera.com/docs/specs/presto2.10/#m274 现在也是全小写的transitionend。见dev.w3.org/csswg/css3-transitions/#transition-events 我删除了 MsTransition 位,但将保留其余答案。所有主要的非 WebKit 浏览器的当前版本都不需要供应商前缀。 transitiontransitionend 就足够了。见:caniuse.com/#search=transitions 为什么要重新定义undefined @Atav32,我也想知道。我唯一能想到的就是它的存在,以防其他人已经将它重新定义为某种东西。【参考方案5】:

更新

以下是一种更清洁的方式,不需要modernizr

$(".myClass").one('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd', 
function() 
 //do something
);

或者

var transEndEventNames = 
        'WebkitTransition': 'webkitTransitionEnd',
        'MozTransition': 'transitionend',
        'OTransition': 'oTransitionEnd otransitionend',
        'msTransition': 'MSTransitionEnd',
        'transition': 'transitionend'
    , transitionEnd = transEndEventNames[Modernizr.prefixed('transition')];

这是基于 Modernizr 建议的代码,但对于新版本的 Opera 有额外的事件。

http://modernizr.com/docs/#prefixed

【讨论】:

这是一个很好的方法,但它需要 Modernizr。这可以简单地编写但没有 Modernizr 吗? jQuery 版本在基于 Webkit 的浏览器中触发两个事件(至少)。 @Dan 我用一个而不是 on 所以它只会触发一次 抱歉,我没有注意到您使用的是 one 而不是 on。太明显了!【参考方案6】:

如果您使用 jQuery 和 Bootstrap,$.support.transition.end 将返回当前浏览器的正确事件。

它是 defined in Bootstrap 并用于 its animation callbacks,尽管 jQuery 文档说不要依赖这些属性:

虽然下面记录了其中一些属性,但它们不会受到长期弃用/删除周期的影响,并且一旦内部 jQuery 代码不再需要它们,它们可能会被删除。

http://api.jquery.com/jQuery.support/

【讨论】:

作为这里最简单的解决方案,有这样一个警告真是太可惜了。 在他们的代码中添加了github.com/twbs/bootstrap/blob/…【参考方案7】:

谷歌关闭确保您不必这样做。如果你有一个元素:

goog.events.listen(element, goog.events.EventType.TRANSITIONEND, function(event) 
  // ... your code here
);

看goog.events.eventtype.js的源码,TRANSITIONEND是通过看useragent来计算的:

// CSS transition events. Based on the browser support described at:
  // https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility
  TRANSITIONEND: goog.userAgent.WEBKIT ? 'webkitTransitionEnd' :
      (goog.userAgent.OPERA ? 'oTransitionEnd' : 'transitionend'),

【讨论】:

【参考方案8】:

截至 2015 年,这个单线应该可以解决问题(IE 10+、Chrome 1+、Safari 3.2+、FF 4+ 和 Opera 12+):-

var transEndEventName = ('WebkitTransition' in document.documentElement.style) ? 'webkitTransitionEnd' : 'transitionend'

附加事件监听器很简单:-

element.addEventListener(transEndEventName , theFunctionToInvoke);

【讨论】:

可爱的解决方案。不幸的是,它不会告诉您是否根本不支持 transitionendvar transEndEventName = ('WebkitTransition' in document.documentElement.style) ? 'webkitTransitionEnd' : ('transitionend' in document.documentElement.style) ? 'transitionend' : false; 然后做一个简单的检查:if(transEndEventName) element.addEventlistener(transEndEventName, theFunctionToInvoke) 我认为应该单独检查:***.com/a/29591030/362006 这个答案现在也适用吗? (2016 年 1 月) 刚刚在 IE 11 中测试它返回 false【参考方案9】:

jquery 覆盖:

(function ($) 
  var oldOn = $.fn.on;

  $.fn.on = function (types, selector, data, fn, /*INTERNAL*/ one) 
    if (types === 'transitionend') 
      types = 'transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd';
    

    return oldOn.call(this, types, selector, data, fn, one);
  ;
)(jQuery);

用法如下:

$('myDiv').on('transitionend', function()  ... );

【讨论】:

【参考方案10】:

这是一种更清洁的方法

 function transitionEvent() 
      // Create a fake element
      var el = document.createElement("div");

      if(el.style.OTransition) return "oTransitionEnd";
      if(el.style.WebkitTransition) return "webkitTransitionEnd";
      return "transitionend";
    

【讨论】:

【参考方案11】:

接受的答案是正确的,但您不必一次又一次地重新创建该元素......

构建一个全局变量并添加函数:

(function(myLib, $, window, document, undefined)

/**
 * @summary
 * Returns the browser's supported animation end event type.
 * @desc
 * @see @link https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/
 * @function myLib.getAnimationEndType
 * @return string The animation end event type
 */
(function()
   var type;

   myLib.getAnimationEndType = function()
      if(!type)
         type = callback();
      return type;

      function callback()
         var t,
             el = document.createElement("fakeelement");

         var animations = 
            "animation"      : "animationend",
            "OAnimation"     : "oAnimationEnd",
            "MozAnimation"   : "animationend",
            "WebkitAnimation": "webkitAnimationEnd"
         

         for (t in animations)
            if (el.style[t] !== undefined)
               return animations[t];
            
         
      
   
());

/**
 * @summary
 * Returns the browser's supported transition end event type.
 * @desc
 * @see @link https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/
 * @function myLib.getTransitionEndType
 * @return string The transition end event type
 */
(function()
   var type;

   myLib.getTransitionEndType = function()
      if(!type)
         type = callback();
      return type;

      function callback()
         var t,
             el = document.createElement("fakeelement");

         var transitions = 
            "transition"      : "transitionend",
            "OTransition"     : "oTransitionEnd",
            "MozTransition"   : "transitionend",
            "WebkitTransition": "webkitTransitionEnd"
         

         for (t in transitions)
            if (el.style[t] !== undefined)
               return transitions[t];
            
         
      
   
());

(window.myLib = window.myLib || , jQuery, window, document));

【讨论】:

以上是关于如何规范跨浏览器的 CSS3 过渡结束事件?的主要内容,如果未能解决你的问题,请参考以下文章

webkit 过渡在 Mozilla 和 Opera 中结束?

Sass与Compress实战:第五章

模仿 IE 中的 CSS3 过渡?

CSS 圆角 - CSS3 //跨浏览器

CSS 跨浏览器CSS3边框半径(圆角)

HTML CSS3 Ajax加载跨浏览器