JavaScript 的“onanimationend”的意外行为

问题描述 投票:0回答:1

请看一下这段代码:

const highlight = (element) => {
  element.classList.remove('highlight');
  setTimeout(() => {
    element.classList.add('highlight');
  }, 0);
  element.onanimationend = () => {
    element.classList.remove('highlight');
  }
}
document.querySelector('body').addEventListener('click', event => {
  if (event.target.hash) {
    event.preventDefault();
    const element = document.querySelector(event.target.hash);
    highlight(element);
  }
});
@keyframes highlight {
  from {
    background: red;
  }
  to {
    background: white;
  }
}
.highlight {
  animation: highlight 5s;
}
<ul>
  <li>
    <a href="#foo">Foo</a>
    <div>
      <ul>
        <li>
          <a href="#foo-1">Foo 1</a>
        </li>
        <li>
          <a href="#foo-2">Foo 2</a>
        </li>
        <li>
          <a href="#foo-3">Foo 3</a>
        </li>
      </ul>
    </div>
  </li>
  <li>
    <a href="#bar">Bar</a>
  </li>
  <li>
    <a href="#baz">Baz</a>
  </li>
</ul>

<hr>

<div id="foo">
  <h2>Foo</h2>
  <ul>
    <li id="foo-1">Foo 1</li>
    <li id="foo-2">Foo 2</li>
    <li id="foo-3">Foo 3</li>
  </ul>
</div>

<div id="bar">
  <h2>Bar</h2>
</div>

<div id="baz">
  <h2>Baz</h2>
</div>

然后请运行代码片段(最好在整页上)并尝试:

点击“Foo”,等待一两秒,点击“Foo 1”,再等待一秒,点击“Foo 2”,等待一秒,再次点击“Foo 2”,等待一秒,点击“富 3 英寸。一切都按预期进行。

现在点击“Foo 1”(或“Foo 2”或“Foo 3”),等待3秒,然后点击“Foo”。如您所见,“Foo”的背景色动画与“Foo 1”(或“Foo 2”或“Foo 3”)的背景色动画同时结束。也可以说 CSS 类“highlight”从“Foo”中删除得太早了。

这是为什么以及如何解决这个问题?

javascript css animation
1个回答
0
投票

问题是因为

animationend
事件正在 DOM 上传播。这意味着,如果动画在父级
li
之前在子级
div
上结束,则该事件将从
li
向上遍历 DOM,并被
div
上的事件处理程序捕获,同时还会删除
.highlight
在那里上课。

要解决此问题,请在

stopPropagation()
处理程序中对事件调用
animationend

const highlight = (element) => {
  element.classList.remove('highlight');
  setTimeout(() => {
    element.classList.add('highlight');
  }, 0);
  element.onanimationend = e => {
    e.stopPropagation();
    element.classList.remove('highlight');
  }
}
document.querySelector('body').addEventListener('click', event => {
  if (event.target.hash) {
    event.preventDefault();
    const element = document.querySelector(event.target.hash);
    highlight(element);
  }
});
@keyframes highlight {
  from {
    background: red;
  }
  to {
    background: white;
  }
}

.highlight {
  animation: highlight 5s;
}
<ul>
  <li>
    <a href="#foo">Foo</a>
    <div>
      <ul>
        <li><a href="#foo-1">Foo 1</a></li>
        <li><a href="#foo-2">Foo 2</a></li>
        <li><a href="#foo-3">Foo 3</a></li>
      </ul>
    </div>
  </li>
  <li><a href="#bar">Bar</a></li>
  <li><a href="#baz">Baz</a></li>
</ul>

<hr>

<div id="foo">
  <h2>Foo</h2>
  <ul>
    <li id="foo-1">Foo 1</li>
    <li id="foo-2">Foo 2</li>
    <li id="foo-3">Foo 3</li>
  </ul>
</div>

<div id="bar">
  <h2>Bar</h2>
</div>

<div id="baz">
  <h2>Baz</h2>
</div>

© www.soinside.com 2019 - 2024. All rights reserved.