Bagaimana cara menormalkan fungsi Transisi CSS3 di seluruh browser?


91

Peristiwa akhir transisi Webkit disebut webkitTransitionEnd, Firefox adalah transisiEnd, opera adalah oTransitionEnd. Apa cara yang baik untuk menangani semuanya dalam JS murni? Haruskah saya melakukan browser sniffing? atau menerapkan masing-masing secara terpisah? Cara lain yang tidak terpikir oleh saya?

yaitu:

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

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

atau

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

function fn() {
   //do whatever
}

Untuk tujuan apakah yang salah?
hubungi saya

Jawaban:


166

Ada teknik yang digunakan di Modernizr, ditingkatkan:

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

Kemudian Anda bisa memanggil fungsi ini kapan pun Anda membutuhkan peristiwa akhir transisi:

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

3
oTransitionEnd diturunkan menjadi otransitionend di Opera. Lihat opera.com/docs/specs/presto2.10/#m274
vieron

1
itu juga transisiend dalam huruf kecil semua sekarang. Lihat dev.w3.org/csswg/css3-transitions/#transition-events
Gossi

1
Saya menghapus sedikit MsTransition, tetapi akan membiarkan sisa jawaban tetap bijaksana. Versi saat ini dari semua browser non-WebKit utama tidak memerlukan prefiks vendor. transitiondan transitionendcukup. Lihat: caniuse.com/#search=transitions
webinista

4
Mengapa perlu didefinisikan ulang undefined?
Atav32

1
@ Atav32, saya juga bertanya-tanya. Satu-satunya hal yang dapat saya pikirkan adalah bahwa itu ada di sana seandainya orang lain mendefinisikannya kembali menjadi sesuatu.
Kuantitas

22

Sesuai komentar Matijs, cara termudah untuk mendeteksi peristiwa transisi adalah dengan pustaka, jquery dalam hal ini:

$("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')
});

Dalam javascript tanpa perpustakaan, ia menjadi sedikit bertele-tele:

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

function callfunction() {
   //do whatever
}

Yang kedua dari yang terakhir itu tidak boleh CamelCased.
wwaawaw

7
cukup lucu, saya datang ke sini karena kolega saya baru saja menemukan beberapa peristiwa yang dilemparkan ke dalam kode mereka yang terlihat persis seperti jawaban ini
depoulo

1
@Duopixel harap uji jawaban Anda dan pertimbangkan untuk mengubahnya, karena ini melempar dua peristiwa di Chrome dan Safari (dan setidaknya semua browser Webkit lain ditambah firefox dan opera lama). msTransitionendtidak dibutuhkan di sini.
Dan

1
Ini akan memicu beberapa peristiwa jika Anda memiliki lebih dari satu properti yang ditransisikan. Lihat: stackoverflow.com/a/18689069/740836
Nick Budden

8

Memperbarui

Berikut ini adalah cara yang lebih bersih untuk melakukannya, dan tidak memerlukan modernisasi

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

kalau tidak

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

Ini didasarkan pada kode yang disarankan oleh Modernizr, tetapi dengan acara tambahan untuk versi Opera yang lebih baru.

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


1
Ini adalah cara terbaik untuk melakukannya tetapi membutuhkan Modernizr. Bisakah ini ditulis sederhana tetapi tanpa Modernizr?
alt

2
Versi jQuery mengaktifkan dua peristiwa di browser berbasis Webkit (setidaknya).
Dan

2
@Dan saya menggunakan satu alih-alih aktif sehingga hanya akan menyala sekali
Tom

Maaf, saya tidak melihat Anda memiliki onebukan on. Itu sangat jelas!
Dan

8

Jika Anda menggunakan jQuery dan Bootstrap $.support.transition.endakan mengembalikan acara yang tepat untuk browser saat ini.

Ini didefinisikan di Bootstrap dan digunakan dalam callback animasinya , meskipun dokumen jQuery mengatakan untuk tidak mengandalkan properti ini:

Meskipun beberapa properti ini didokumentasikan di bawah ini, properti tersebut tidak mengalami siklus penghentian / penghapusan yang lama dan dapat dihapus setelah kode jQuery internal tidak lagi membutuhkannya.

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


2
Menjadi solusi paling sederhana di sini, sangat disayangkan ini memiliki peringatan seperti itu.
Ninjakannon

1
Itu ditambahkan dalam kode mereka di sini github.com/twbs/bootstrap/blob/…
Tom

6

Pada 2015, satu baris ini harus melakukan kesepakatan (IE 10+, Chrome 1+, Safari 3.2+, FF 4+ dan Opera 12 +): -

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

Melampirkan pendengar acara itu sederhana: -

element.addEventListener(transEndEventName , theFunctionToInvoke);

Solusi yang bagus. Sayangnya itu tidak akan memberi tahu Anda jika transitionendtidak didukung sama sekali: var transEndEventName = ('WebkitTransition' in document.documentElement.style) ? 'webkitTransitionEnd' : ('transitionend' in document.documentElement.style) ? 'transitionend' : false; Dan kemudian lakukan pemeriksaan sederhana: if(transEndEventName) element.addEventlistener(transEndEventName, theFunctionToInvoke)
Luuuud

Saya pikir itu harus diperiksa secara terpisah: stackoverflow.com/a/29591030/362006
Salman von Abbas

Apakah jawaban ini juga berlaku untuk sekarang? (Jan 2016)
Jessica

Baru saja mengujinya di IE 11 dan hasilnya palsu
Jessica

1

Yang kedua adalah cara untuk pergi. Hanya satu dari peristiwa itu yang akan diaktifkan di setiap browser, jadi Anda dapat menyetel semuanya dan itu akan berhasil.


1

Ini cara yang lebih bersih

 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

penutupan google memastikan Anda tidak perlu melakukan ini. Jika Anda memiliki elemen:

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

melihat sumber goog.events.eventtype.js, TRANSITIONEND dihitung dengan melihat agen pengguna:

// 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

Saya menggunakan kode seperti ini (dengan 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
}

Itu memungkinkan saya menggunakan JS untuk menambahkan sesuatu dengan menentukan vP yang bersentuhan dengan properti, dan jika tidak mengenai browser, itu hanya menggunakan standar. Peristiwa memungkinkan saya mengikat dengan mudah seperti ini:

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

Terima kasih! Saya akhirnya melakukan hal serupa, tetapi tanpa browser sniffing. Anda dapat melihat hasilnya (dan kode) di sini: cssglue.com/cubic . Satu-satunya masalah dengan solusi Anda adalah — jika vendor browser memutuskan untuk menstandarisasi peristiwa transisi mereka — mereka mungkin melepaskan awalannya dan berhenti bekerja (mungkin belum). Tapi ya, itu membuat kodenya jauh lebih bersih.
metode tindakan

Saya setuju, saya sudah lama ingin mengganti milik saya dengan sesuatu yang lebih baik, tetapi di sisi lain saya menyukai kesederhanaannya.
Rich Bradshaw

2
Untuk apa nilainya. Ini dapat dilakukan tanpa mengendus browser hanya dengan melakukanobject.bind('transitionend oTransitionEnd webkitTransitionEnd', function() { // callback } );
Matijs

1
Versi acara yang tidak diawali dinamai transitionend, bukan TransitionEnd.
mgol

0

jquery override:

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

dan penggunaan seperti:

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

0

Jawaban yang diterima benar tetapi Anda tidak perlu membuat ulang elemen itu lagi dan lagi dan ...

Bangun variabel global dan tambahkan fungsi:

(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));
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.