Làm cách nào để chuẩn hóa các chức năng Chuyển đổi CSS3 trên các trình duyệt?


91

Sự kiện kết thúc quá trình chuyển đổi của Webkit được gọi là webkitTransitionEnd, Firefox là chuyển tiếpEnd, toán hạng là oTransitionEnd. Cách tốt để giải quyết tất cả chúng trong JS thuần túy là gì? Tôi có nên kiểm tra trình duyệt không? hoặc thực hiện từng cái riêng biệt? Một số cách khác đã không xảy ra với tôi?

I E:

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

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

hoặc là

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

function fn() {
   //do whatever
}

Vì mục đích gì là sai?
call-me

Câu trả lời:


166

Có một kỹ thuật được sử dụng trong Modernizr, đã được cải thiện:

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

Sau đó, bạn chỉ có thể gọi hàm này bất cứ khi nào bạn cần sự kiện kết thúc chuyển đổi:

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

3
oTransitionEnd được viết thường thành otransitionend trong Opera. Xem opera.com/docs/specs/presto2.10/#m274
vieron,

1
bây giờ nó cũng được chuyển thành chữ thường. Xem dev.w3.org/csswg/css3-transitions/#transition-events
gossi

1
Tôi đã xóa bit MsTransition, nhưng sẽ giữ nguyên phần còn lại của câu trả lời. Các phiên bản hiện tại của tất cả các trình duyệt chính không phải WebKit không yêu cầu tiền tố nhà cung cấp. transitiontransitionendlà đủ. Xem: caniuse.com/#search=transitions
webinista

4
Tại sao nó cần phải xác định lại undefined?
Atav32

1
@ Atav32, tôi cũng thắc mắc điều đó. Điều duy nhất tôi có thể nghĩ là nó ở đó trong trường hợp người khác đã định nghĩa lại nó thành một thứ gì đó.
Qtax

22

Theo nhận xét của Matijs, cách dễ nhất để phát hiện các sự kiện chuyển tiếp là sử dụng thư viện, jquery trong trường hợp này:

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

Trong javascript ít thư viện, nó có một chút dài dòng:

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

function callfunction() {
   //do whatever
}

Cái thứ hai đến cuối cùng không nên là CamelCased.
wwaawaw

7
buồn cười thay, tôi đến đây 'vì các đồng nghiệp của tôi vừa phát hiện ra nhiều sự kiện được đưa vào mã của họ trông giống hệt như câu trả lời này
depoulo

1
@Duopixel vui lòng kiểm tra câu trả lời của bạn và cân nhắc thay đổi câu trả lời vì nó ném hai sự kiện trong Chrome và Safari (và ít nhất là tất cả các trình duyệt Webkit khác cùng với firefox và opera cũ). msTransitionendkhông cần thiết ở đây.
Dan

1
Nó sẽ kích hoạt nhiều sự kiện nếu bạn có nhiều thuộc tính được chuyển đổi. Xem: stackoverflow.com/a/18689069/740836
Nick Budden

8

Cập nhật

Sau đây là một cách làm dễ dàng hơn và không yêu cầu hiện đại hóa

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

Ngoài ra

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

Điều này dựa trên mã do Modernizr đề xuất, nhưng với sự kiện bổ sung cho các phiên bản Opera mới hơn.

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


1
Đây là một cách tuyệt vời để làm điều đó nhưng nó yêu cầu Modernizr. Điều này có thể được viết đơn giản nhưng không có Modernizr?
alt

2
Phiên bản jQuery kích hoạt hai sự kiện trong các trình duyệt dựa trên Webkit (ít nhất).
Dan

2
@ Tôi có thể sử dụng một cái thay vì trên vì vậy nó sẽ chỉ kích hoạt một lần
Tom

Xin lỗi, tôi không nhận thấy bạn có onethay vì on. Nó đã quá rõ ràng!
Dan

8

Nếu bạn sử dụng jQuery và Bootstrap $.support.transition.end sẽ trả về sự kiện phù hợp cho trình duyệt hiện tại.

Nó được định nghĩa trong Bootstrap và được sử dụng trong các lệnh gọi lại hoạt ảnh của nó , mặc dù các tài liệu jQuery nói rằng không dựa vào các thuộc tính này:

Mặc dù một số thuộc tính này được trình bày dưới đây, nhưng chúng không phải tuân theo chu kỳ ngừng sử dụng / xóa lâu dài và có thể bị xóa sau khi mã jQuery nội bộ không còn cần đến chúng nữa.

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


2
Là giải pháp đơn giản nhất ở đây, thật xấu hổ vì điều này có một cảnh báo trước.
Ninjakannon

1
Nó được thêm vào mã của họ tại đây github.com/twbs/bootstrap/blob/…
Tom,

6

Kể từ năm 2015, một lớp lót này sẽ thực hiện thỏa thuận (IE 10+, Chrome 1+, Safari 3.2+, FF 4+ và Opera 12 +): -

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

Việc đính kèm trình nghe sự kiện rất đơn giản: -

element.addEventListener(transEndEventName , theFunctionToInvoke);

Giải pháp đáng yêu. Đáng tiếc là nó sẽ không cho bạn biết nếu transitionendkhông được hỗ trợ ở tất cả: var transEndEventName = ('WebkitTransition' in document.documentElement.style) ? 'webkitTransitionEnd' : ('transitionend' in document.documentElement.style) ? 'transitionend' : false; Và sau đó làm một kiểm tra đơn giản: if(transEndEventName) element.addEventlistener(transEndEventName, theFunctionToInvoke)
Luuuud

Tôi nghĩ điều đó nên được kiểm tra riêng: stackoverflow.com/a/29591030/362006
Salman von Abbas

Câu trả lời này có áp dụng cho cả bây giờ không? (Tháng 1 năm 2016)
Jessica

Chỉ cần thử nghiệm nó trong IE 11 và nó trở lại sai
Jessica

1

Thứ hai là con đường đi. Chỉ một trong những sự kiện đó sẽ kích hoạt trong mọi trình duyệt, vì vậy bạn có thể thiết lập tất cả chúng và nó sẽ hoạt động.


1

Đây là một cách sạch hơn

 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 đóng đảm bảo bạn không phải làm điều này. Nếu bạn có một phần tử:

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

nhìn vào nguồn của goog.events.eventtype.js, TRANSITIONEND được tính bằng cách xem 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

Tôi sử dụng mã như thế này (với 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
}

Điều đó cho phép tôi sử dụng JS để thêm mọi thứ bằng cách chỉ định vP được kết hợp với thuộc tính và nếu nó không trúng trình duyệt, nó chỉ sử dụng tiêu chuẩn. Các sự kiện cho phép tôi dễ dàng liên kết như vậy:

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

Cảm ơn! Cuối cùng tôi đã làm điều gì đó tương tự, nhưng không bị trình duyệt đánh hơi. Bạn có thể xem kết quả (và mã) tại đây: cssglue.com/cubic . Vấn đề duy nhất với giải pháp của bạn là — nếu các nhà cung cấp trình duyệt quyết định độc lập các sự kiện chuyển đổi của họ — họ có thể bỏ tiền tố và chúng sẽ ngừng hoạt động (chưa chắc đã xảy ra). Nhưng có, nó làm cho mã sạch hơn nhiều.
methodofaction

Tôi đồng ý, tôi đã có ý định thay thế của tôi bằng một cái gì đó tốt hơn, nhưng mặt khác tôi thích sự đơn giản của nó.
Rich Bradshaw

2
Cho những gì nó có giá trị. Điều này có thể được thực hiện mà không cần trình duyệt sniffing bởi chỉ cần làmobject.bind('transitionend oTransitionEnd webkitTransitionEnd', function() { // callback } );
Matijs

1
Phiên bản không có tiền tố của sự kiện được đặt tên transitionend, không phải TransitionEnd.
mgol

0

ghi đè 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);

và cách sử dụng như:

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

0

Câu trả lời được chấp nhận là đúng nhưng bạn không phải tạo lại phần tử đó nhiều lần-và ...

Xây dựng một biến toàn cục và thêm (các) hàm:

(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));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.