ฉันจะทำให้ฟังก์ชันการเปลี่ยน CSS3 เป็นปกติในเบราว์เซอร์ได้อย่างไร


91

เหตุการณ์สิ้นสุดการเปลี่ยนแปลงของ Webkit เรียกว่า webkitTransitionEnd, Firefox คือ transitionEnd โอเปร่าคือ 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
}

เท็จเพื่อจุดประสงค์ใด?
โทรหาฉัน

คำตอบ:


166

มีเทคนิคที่ใช้ใน 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);

3
oTransitionEnd ถูกลดขนาดเป็น otransitionend ใน Opera ดูopera.com/docs/specs/presto2.10/#m274
vieron

1
ตอนนี้ยังเปลี่ยนเป็นตัวพิมพ์เล็กทั้งหมด ดูdev.w3.org/csswg/css3-transitions/#transition-events
gossi

1
ฉันลบบิต MsTransition ออก แต่จะปล่อยให้คำตอบที่เหลืออยู่ในชั้นเชิง เวอร์ชันปัจจุบันของเบราว์เซอร์ที่ไม่ใช่ WebKit หลักทั้งหมดไม่จำเป็นต้องมีคำนำหน้าผู้จำหน่าย transitionและtransitionendเพียงพอแล้ว ดู: caniuse.com/#search=transitions
webinista

4
ทำไมต้องกำหนดใหม่undefined?
Atav32

1
@ Atav32 ฉันก็สงสัยเหมือนกัน สิ่งเดียวที่ฉันคิดได้ก็คือมันอยู่ที่นั่นในกรณีที่มีคนนิยามใหม่ให้กับบางสิ่งที่มีอยู่แล้ว
Qtax

22

ตามความคิดเห็นของ 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')
});

ในจาวาสคริปต์ที่ไม่ใช้ไลบรารีจะได้รับรายละเอียดเล็กน้อย:

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

function callfunction() {
   //do whatever
}

คนที่สองต่อสุดท้ายไม่ควรเป็นอูฐ
wwaawaw

7
ตลกพอฉันมาที่นี่เพราะเพื่อนร่วมงานของฉันเพิ่งค้นพบเหตุการณ์หลายอย่างถูกโยนลงในรหัสของพวกเขาซึ่งดูเหมือนคำตอบนี้ทุก
ประการ

1
@Duopixel โปรดทดสอบคำตอบของคุณและพิจารณาเปลี่ยนแปลงเนื่องจากมีเหตุการณ์สองเหตุการณ์ใน Chrome และ Safari (และอย่างน้อยเบราว์เซอร์ Webkit อื่น ๆ รวมทั้ง Firefox และ Opera รุ่นเก่า) msTransitionendไม่จำเป็นที่นี่
แดน

1
มันจะทริกเกอร์หลายเหตุการณ์หากคุณมีการเปลี่ยนแปลงมากกว่าหนึ่งคุณสมบัติ ดู: stackoverflow.com/a/18689069/740836
Nick Budden

8

อัปเดต

ต่อไปนี้เป็นวิธีที่สะอาดกว่าและไม่ต้องใช้ความทันสมัย

$(".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


1
นี่เป็นวิธีที่ยอดเยี่ยม แต่ต้องใช้ Modernizr สิ่งนี้สามารถเขียนง่ายๆ แต่ไม่มี Modernizr ได้หรือไม่?
alt

2
เวอร์ชัน jQuery เริ่มการทำงานสองเหตุการณ์ในเบราว์เซอร์ที่ใช้ Webkit (อย่างน้อย)
แดน

2
@ ฉันใช้อันเดียวแทนดังนั้นมันจะยิงเพียงครั้งเดียว
ทอม

ขอโทษนะฉันไม่ได้สังเกตเห็นคุณมีแทนone onเห็นได้ชัดมาก!
แดน

8

หากคุณใช้ jQuery และ Bootstrap $.support.transition.endจะส่งคืนเหตุการณ์ที่ถูกต้องสำหรับเบราว์เซอร์ปัจจุบัน

ถูกกำหนดไว้ใน Bootstrapและใช้ในการเรียกกลับแบบแอนิเมชั่นแม้ว่าเอกสาร jQuery จะบอกว่าไม่ต้องพึ่งพาคุณสมบัติเหล่านี้:

แม้ว่าคุณสมบัติเหล่านี้บางส่วนจะได้รับการบันทึกไว้ด้านล่าง แต่ก็ไม่ได้อยู่ภายใต้วงจรการเลิกใช้งาน / การลบที่ยาวนานและอาจถูกลบออกเมื่อโค้ด jQuery ภายในไม่ต้องการอีกต่อไป

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


2
เป็นทางออกที่ง่ายที่สุดที่นี่มันเป็นความอัปยศที่มีข้อแม้
Ninjakannon

1
มันเพิ่มในโค้ดของพวกเขาที่นี่github.com/twbs/bootstrap/blob/…
ทอม

6

ในปี 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);

ทางออกที่น่ารัก น่าเสียดายที่จะไม่บอกคุณว่าtransitionendไม่รองรับเลยหรือไม่: var transEndEventName = ('WebkitTransition' in document.documentElement.style) ? 'webkitTransitionEnd' : ('transitionend' in document.documentElement.style) ? 'transitionend' : false; จากนั้นตรวจสอบง่ายๆ: if(transEndEventName) element.addEventlistener(transEndEventName, theFunctionToInvoke)
Luuuud

ฉันคิดว่าควรตรวจสอบแยกกัน: stackoverflow.com/a/29591030/362006
Salman von Abbas

คำตอบนี้ใช้ได้กับตอนนี้ด้วยหรือไม่? (ม.ค. 2559)
เจสสิก้า

เพิ่งทดสอบใน IE 11 และส่งคืนเท็จ
เจสสิก้า

1

ประการที่สองคือวิธีที่จะไป มีเพียงเหตุการณ์เดียวเท่านั้นที่จะเริ่มทำงานในทุกเบราว์เซอร์ดังนั้นคุณสามารถตั้งค่าทั้งหมดได้และจะใช้งานได้


1

นี่คือวิธีที่สะอาดกว่า

 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 ทำให้แน่ใจว่าคุณไม่ต้องทำสิ่งนี้ หากคุณมีองค์ประกอบ:

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

0

ฉันใช้รหัสแบบนี้ (กับ 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 ปัญหาเดียวในการแก้ปัญหาของคุณคือหากผู้จำหน่ายเบราว์เซอร์ตัดสินใจที่จะกำหนดเหตุการณ์การเปลี่ยนแปลงเป็นมาตรฐานพวกเขาอาจทิ้งคำนำหน้าและจะหยุดทำงาน (ยังไม่น่าเป็นไปได้) แต่ใช่มันทำให้โค้ดสะอาดขึ้นมาก
methodofaction

ฉันเห็นด้วยฉันตั้งใจจะแทนที่ของฉันด้วยสิ่งที่ดีกว่า แต่ในทางกลับกันฉันชอบความเรียบง่ายของมัน
Rich Bradshaw

2
สำหรับสิ่งที่คุ้มค่า สามารถทำได้โดยไม่ต้องใช้เบราว์เซอร์เพียงแค่ทำobject.bind('transitionend oTransitionEnd webkitTransitionEnd', function() { // callback } );
Matijs

1
รุ่นที่ไม่ใช่คำนำหน้าของเหตุการณ์ที่เป็นชื่อไม่ได้transitionend TransitionEnd
mgol

0

การแทนที่ 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() { ... });

0

คำตอบที่ยอมรับนั้นถูกต้อง แต่คุณไม่จำเป็นต้องสร้างองค์ประกอบนั้นซ้ำแล้วซ้ำอีกและ ...

สร้างตัวแปรส่วนกลางและเพิ่มฟังก์ชัน:

(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));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.