javascript transitionend 事件触发两次

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18689031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 12:53:54  来源:igfitidea点击:

transitionend event fires twice

javascriptcss

提问by Jonathan

I have the following code and my problem is that the transitionendevent is fired twice. I don't know what's causing this. I suspected the vendor prefixes caused it, but they don't. Even if I only leave transitionendand transitionit will still fire twice.

我有以下代码,我的问题是该transitionend事件被触发两次。我不知道是什么原因造成的。我怀疑是供应商前缀引起的,但事实并非如此。即使我只离开transitionendtransition它仍然会发射两次。

CSS

CSS

transition: 1s ease-out;

JS

JS

document.addEventListener('click', function (e) {
    var submarine = document.querySelector('.submarine');
    var submarineX = e.clientX - submarine.offsetWidth / 2;
    var submarineY = e.clientY - submarine.offsetHeight / 2;

    submarine.style.left = submarineX + "px";
    submarine.style.top = submarineY + "px";
});

document.addEventListener('transitionend', function (event) {
    console.log(event.type + " " + new Date().getTime());
});

Fiddle

小提琴

document.addEventListener('transitionend', function (event) {
    console.log(event.type + " " + new Date().getTime());
});

document.addEventListener('click', function (e) {
    var submarine = document.querySelector('.submarine');
    var submarineX = e.clientX - submarine.offsetWidth / 2;
    var submarineY = e.clientY - submarine.offsetHeight / 2;

    submarine.style.left = submarineX + "px";
    submarine.style.top = submarineY + "px";
});
.submarine {
    position: absolute;
    top: 0;
    left: 0;
    width: 20px;
    height: 20px;
    background-color: red;
    border-radius: 50%;
    transition: 1s ease-out;
}
<div class="submarine"></div>

回答by Fabrício Matté

transitionendfires for each property transitioned, in your case topand left.

transitionend在您的情况topleft.

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

您可以在 处访问与事件关联的属性event.propertyName

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

没有“transition send”事件,因此您可能需要一些技巧,例如transitionend仅过滤转换属性之一的回调处理。例如:

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


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

附:没有浏览器触发该MSTransitionEnd事件。它出现在 MS 文档中的某个时候,但在 IE10 测试版发布之前的某个时候,它被标准transitionend事件所取代。

回答by iConnor

The event fires for each property that has been transitioned.

为每个已转换的属性触发该事件。

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

propertyName该法布里西奥建议的方法是做正确的方法,但是这取决于你也可以使用的情况one();为好,像这样的。

$(document).one('transitionend webkitTransitionEnd MSTransitionEnd', function() {
   ...
});

回答by TJ.

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)。这并没有回答这个问题,它确实回答了我登陆这里时所寻找的东西。

CSS:

CSS:

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

JavaScript:

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.

在 IE11、Chrome 48 和 Firefox 37 中测试。

回答by Stoutie

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.

对于仍在寻找更健壮的解决方案(例如“allTransitionEnd”事件)的任何人,我已经实现了一个jQuery“特殊事件”,更多地是作为我正在研究的东西的概念证明,但我可能会在 Github 上发布一个库。

Check out the JSBin.

查看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 transitionendevents (vendor specific included) in order to keep track of properties that have finished transitioning. When all have finished transitioning it triggers any bound allTransitionsEndhandlers and then clears transition properties, in case they've changed as well, and probes for them fresh next time around.

它通过探测元素的转换属性来工作,然后绑定到本机transitionend事件(包括特定于供应商)以跟踪已完成转换的属性。当所有都完成转换后,它会触发任何绑定allTransitionsEnd处理程序,然后清除转换属性,以防它们也发生了变化,并在下次重新探测它们。

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.
  • 淡出和缩小后删除 Flash 消息。
  • 在可重用组件(例如菜单或模式)中触发“打开”和“关闭”事件,消费者可能希望在转换结束后执行某些逻辑,而无需探查 css 转换。

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.

适用于最新版本的 Chrome、Firefox、Safari、Mobile Safari 以及 IE11 和 IE10。在 IE8 中不起作用,因为不支持转换。绑定到其他本地事件作为回退。

回答by Etienne Martin

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

您可以使用该target属性过滤掉由子元素propertyName触发的事件,并仅在特定属性更改时才触发该事件。

const handleTransitionEnd = event => {
  if (event.target !== myDomElementRef) return;
  if (event.propertyName !== "height") return;

  // Do my things
};

回答by rotaercz

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