Tarayıcılar arasında CSS3 Geçiş işlevlerini nasıl normalleştiririm?


91

Webkit'in geçiş bitiş olayına webkitTransitionEnd, Firefox geçişEnd, opera oTransitionEnd olarak adlandırılır. Bunların hepsini saf JS'de ele almanın iyi bir yolu nedir? Tarayıcı koklama yapmalı mıyım? veya her birini ayrı ayrı uygulayabilir misiniz? Aklıma gelmeyen başka bir yol?

yani:

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

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

veya

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

function fn() {
   //do whatever
}

Yanlış ne amaçla?
beni

Yanıtlar:


166

Modernizr'de geliştirilmiş bir teknik var:

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'; 
}

Ardından, geçiş bitiş olayına ihtiyaç duyduğunuzda bu işlevi çağırabilirsiniz:

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

3
oTransitionEnd, Opera'da otransitionend'e küçültüldü. Bkz opera.com/docs/specs/presto2.10/#m274
vieron

1
aynı zamanda artık tüm küçük harflerin geçişidir. Bkz. Dev.w3.org/csswg/css3-transitions/#transition-events
gossi

1
MsTransition bitini kaldırdım, ancak cevabın geri kalanını dokunaklı olarak bırakacağım. Tüm büyük WebKit olmayan tarayıcıların geçerli sürümleri bir satıcı öneki gerektirmez. transitionve transitionendyeter. Bakınız: caniuse.com/#search=transitions
webinista

4
Neden yeniden tanımlanması gerekiyor undefined?
Atav32

1
@ Atav32, bunu da merak ediyorum. Aklıma gelen tek şey, başka birinin onu zaten bir şeye yeniden tanımlaması durumunda orada olmasıdır.
Qtax

22

Matijs'in yorumuna göre, geçiş olaylarını tespit etmenin en kolay yolu bir kitaplıktır, bu durumda 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')
});

Kitaplıksız javascript'te biraz ayrıntılı olur:

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

function callfunction() {
   //do whatever
}

Sondan ikinciye deve kılıflı olmamalı.
wwaawaw

7
yeterince komik, buraya geldim çünkü meslektaşlarım kodlarında tam olarak bu yanıta benzeyen birden fazla olayın atıldığını keşfetti
depoulo

1
@ Duopixel, lütfen yanıtınızı test edin ve değiştirmeyi düşünün, çünkü Chrome ve Safari'de (ve en azından diğer tüm Webkit tarayıcılarının yanı sıra eski firefox ve opera) iki olay atar. msTransitionendburada gerekli değildir.
Dan

1
Birden fazla mülkün geçişini yaptıysanız, birden çok etkinliği tetikler. Bakınız: stackoverflow.com/a/18689069/740836
Nick Budden

8

Güncelleme

Aşağıdakiler bunu yapmanın daha temiz bir yoludur ve modernizasyon gerektirmez

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

Alternatif olarak

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

Bu, Modernizr tarafından önerilen koda dayanmaktadır, ancak Opera'nın daha yeni sürümleri için ekstra etkinlikle birlikte.

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


1
Bu, bunu yapmanın harika bir yoludur ancak Modernizr gerektirir. Bu basitçe ama Modernizr olmadan yazılabilir mi?
alternatif

2
jQuery sürümü, Webkit tabanlı tarayıcılarda (en azından) iki olay tetikler.
Dan

2
@Dan, yerine bir tane kullanıyorum, bu yüzden sadece bir kez ateş edecek
Tom

Maalesef, oneyerine olduğunu fark etmedim on. Çok açıktı!
Dan

8

JQuery kullanıyorsanız ve Bootstrap $.support.transition.endgeçerli tarayıcı için doğru olayı döndürür.

O edilir Bootstrap tanımlanan ve kullanılan onun animasyon geri aramaları jQuery dokümanlar bu özelliklere güvenmek değil demek olsa da,:

Bu özelliklerden bazıları aşağıda belgelenmiş olsa da, uzun bir kullanımdan kaldırma / kaldırma döngüsüne tabi değildirler ve dahili jQuery kodu artık bunlara ihtiyaç duymadığında kaldırılabilir.

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


2
Buradaki en basit çözüm olarak, bunun böyle bir uyarısı olması gerçekten utanç verici.
Ninjakannon

1
Buradaki kodlarına
Tom

6

2015 itibariyle, bu tek astar anlaşmayı yapmalıdır (IE 10+, Chrome 1+, Safari 3.2+, FF 4+ ve Opera 12 +): -

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

Olay dinleyicisini eklemek basittir: -

element.addEventListener(transEndEventName , theFunctionToInvoke);

Güzel çözüm. Maalesef transitionendhiç desteklenip desteklenmediğini size söylemez : var transEndEventName = ('WebkitTransition' in document.documentElement.style) ? 'webkitTransitionEnd' : ('transitionend' in document.documentElement.style) ? 'transitionend' : false; Ve sonra basit bir kontrol yapın: if(transEndEventName) element.addEventlistener(transEndEventName, theFunctionToInvoke)
Luuuud

Bunun ayrıca kontrol edilmesi gerektiğini düşünüyorum: stackoverflow.com/a/29591030/362006
Salman von Abbas

Bu cevap şimdi için de geçerli mi? (Ocak 2016)
Jessica

IE 11'de test ettim ve yanlış çıktı
Jessica

1

İkincisi, gitmenin yoludur. Her tarayıcıda bu olaylardan yalnızca biri tetiklenecek, böylece hepsini ayarlayabilirsiniz ve çalışacaktır.


1

İşte daha temiz bir yol

 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";
    }

0

google kapatması, bunu yapmanız gerekmediğinden emin olmanızı sağlar. Bir elementiniz varsa:

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

goog.events.eventtype.js kaynağına bakıldığında, GEÇİŞEND, kullanıcı aracısına bakılarak hesaplanır:

// 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'),

0

Böyle bir kod kullanıyorum (jQuery ile)

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
}

Bu, özellik ile bağlantılı vP belirleyerek bir şeyler eklemek için JS kullanmama izin veriyor ve bir tarayıcıya çarpmadıysa sadece standardı kullanıyor. Olaylar kolayca şu şekilde bağlanmama izin veriyor:

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

Teşekkürler! Ben de benzer bir şey yaptım ama tarayıcı koklamadan. Sonucu (ve kodu) burada görebilirsiniz: cssglue.com/cubic . Çözümünüzle ilgili tek sorun, tarayıcı satıcıları geçiş olaylarını standartlaştırmaya karar verirlerse, öneklerini bırakabilirler ve çalışmayı durdurabilirler (henüz pek olası değildir). Ama evet, kodu çok daha temiz hale getiriyor.
methodofaction

Katılıyorum, benimkini daha iyi bir şeyle değiştirmeyi düşünüyordum, ama öte yandan basitliğini seviyorum.
Rich Bradshaw

2
Değeri ne olursa olsun. Bu, tarayıcı object.bind('transitionend oTransitionEnd webkitTransitionEnd', function() { // callback } );
koklamadan

1
Olayın önekli olmayan versiyonu adlandırılır transitionend, isimlendirilmez TransitionEnd.
mgol

0

jquery geçersiz kılma:

(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);

ve aşağıdaki gibi kullanım:

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

0

Kabul edilen cevap doğrudur ancak bu öğeyi tekrar tekrar oluşturmanız gerekmez ve ...

Global bir değişken oluşturun ve işlevleri ekleyin:

(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));
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.