transitionend event fires twice

后端 未结 6 778
渐次进展
渐次进展 2020-12-04 19:33

I have the following code and my problem is that the transitionend event is fired twice. I don\'t know what\'s causing this. I suspected the vendor prefixes cau

相关标签:
6条回答
  • 2020-12-04 20:05

    For anyone still looking for a more robust solution, like "allTransitionEnd" event, I've implemented a jQuery "special event", more as a proof of concept for something I was working on, but I might put out a lib on Github.

    Check out the JSBin.

    It's quite tricky, so I won't explain too much, but it makes it real easy to do stuff after ALL transitions have ended on an element:

    $(function () {
    
        $element.on('allTransitionEnd', function () {
            // do something after all transitions end.
        });
    
    });
    

    It works by probing the element for transition properties, then binds to the native transitionend events (vendor specific included) in order to keep track of properties that have finished transitioning. When all have finished transitioning it triggers any bound allTransitionsEnd handlers and then clears transition properties, in case they've changed as well, and probes for them fresh next time around.

    This is really useful when multiple properties are being transitioned with varying delay and/or duration and you want to do something after all transitions have completed.

    Example use cases:

    • Remove a flash message after fade-out and shrink.
    • Triggering "opened" and "closed" events in a reusable component, such as a menu or modal, where consumers may want to execute some logic after the transition has ended, without prying into css transitions.

    If you are only transitioning one property, or have no varied delays and/or durations, then a simple solution works fine.

    Works in latest version of Chrome, Firefox, Safari, Mobile Safari and IE11 and IE10. Doesn't work in IE8 because transitions are not supported. Bind to an additional native event as fallback.

    0 讨论(0)
  • 2020-12-04 20:11

    transitionend fires for each property transitioned, in your case top and left.

    You can access the property associated with the event at event.propertyName.

    There's no "transitionsend" event, so you will probably need some hackiness such as filtering the transitionend callback handling for only one of the transitioned properties. E.g.:

    function (event) {
        if (event.propertyName == 'top') {
            //put your code here
        }
    });
    

    ps. No browser fires the MSTransitionEnd event. It was at some point in the MS docs, but sometime before the IE10 beta release it was replaced by the standard transitionend event.

    0 讨论(0)
  • 2020-12-04 20:11

    This is a relatively old question but I thought I'd share my answer:

    function OnTransitionEvent() {
        var t,
            el = document.createElement('transitionElement');
    
        var transitions = {
            'transition'      : 'transitionend',
            'OTransition'     : 'oTransitionEnd',
            'MozTransition'   : 'transitionend',
            'WebkitTransition': 'webkitTransitionEnd'
        };
    
        for (t in transitions){
            if (el.style[t] !== undefined){
                return transitions[t];
            }
        }
    }
    
    var transitionEvent = OnTransitionEvent();
    
    $(document).one(transitionEvent, function() { 
        console.log('done');
    });
    
    0 讨论(0)
  • 2020-12-04 20:12

    For anyone looking for a simple, one time copy and paste solution (I've only included the necessary css). This doesn't answer the question and it does answer what I was looking for when I landed here.

    CSS:

    .my-elem {
        transition: height 0.5s ease-out, opacity 0.5s ease-out;
    }
    

    JavaScript:

    var elem = document.querySelector(".my-elem");
    
    var transitionCounter = 0;
    
    var transitionProp = window.getComputedStyle(elem , null)["transition-property"] || "";
    
    // We just need to know how many transitions there are
    var numTransitionProps = transitionProp.split(",").length;
    
    elem.addEventListener("transitionend", (event) => {
      // You could read event.propertyName to find out which transition was ended, 
      // but it's not necessary if you just want to know when they are all done.
      if (transitionCounter < (numTransitionProps - 1)) {
        transitionCounter++;
      } else {
        transitionCounter = 0; // reset
        alert("I'm done!!!"); // do what you need to
      }
    }, false);
    

    Tested in IE11, Chrome 48 and Firefox 37.

    0 讨论(0)
  • 2020-12-04 20:28

    You can use the target property to filter out events that are triggered by child elements and use propertyName to only trigger the event when a specific property changed.

    const handleTransitionEnd = event => {
      if (event.target !== myDomElementRef) return;
      if (event.propertyName !== "height") return;
    
      // Do my things
    };
    
    0 讨论(0)
  • 2020-12-04 20:29

    The event fires for each property that has been transitioned.

    The propertyName way that Fabricio suggested is the proper way to do this, however depending on the circumstances you can also use one(); as well, like this.

    $(document).one('transitionend webkitTransitionEnd MSTransitionEnd', function() {
       ...
    });
    
    0 讨论(0)
提交回复
热议问题