使用 onclick 单击子元素时,Intersection Observer 的关键帧动画会意外运行

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

我希望 css 关键帧动画在桥元素位于视口中时运行 1 次。相交观察器在这方面做得很好,但问题是当单击具有 onClicks 的元素的其他部分以显示新文本段落时,动画会随机触发。

重点是要引起用户注意,嘿!当主元素处于视图中时,您可以通过显示延迟的框阴影来单击桥元素的这些部分。也许有更好的方法来向用户显示一个区域是可点击的,也许有一个我忽略的 JS 规则?任何建议表示赞赏 - 谢谢!

示例: https://codepen.io/robyngraha/pen/LYaZMVg

function firstBro() {
  document.getElementById("first-bro-text").style.display = "block";
  document.getElementById("second-bro-text").style.display = "none";
  document.getElementById("third-bro-text").style.display = "none";
  document.getElementById("first-brother").classList.add("bridge-green");
  document.getElementById("second-brother").classList.remove("bridge-green");
  document.getElementById("third-brother").classList.remove("bridge-green");
}

function secondBro() {
  document.getElementById("first-bro-text").style.display = "none";
  document.getElementById("second-bro-text").style.display = "block";
  document.getElementById("third-bro-text").style.display = "none";
  document.getElementById("first-brother").classList.remove("bridge-green");
  document.getElementById("second-brother").classList.add("bridge-green");
  document.getElementById("third-brother").classList.remove("bridge-green");
}

function thirdBro() {
  document.getElementById("first-bro-text").style.display = "none";
  document.getElementById("second-bro-text").style.display = "none";
  document.getElementById("third-bro-text").style.display = "block";
  document.getElementById("first-brother").classList.remove("bridge-green");
  document.getElementById("second-brother").classList.remove("bridge-green");
  document.getElementById("third-brother").classList.add("bridge-green");
}

// animation
const bridge = document.querySelector('.bridge');
const secondBroEl = document.querySelector('#second-brother');
const thirdBroEl = document.querySelector('#third-brother');
const observer = new IntersectionObserver(entries => {
  secondBroEl.classList.toggle('animation', entries[0].isIntersecting);
  thirdBroEl.classList.toggle('animation2', entries[0].isIntersecting);
  console.log(entries)
});

observer.observe(bridge);
.scroll-container {
  max-width: 480px;
}


/* Bridge CSS */

.bridge-container {
  height: 65px;
  color: white;
  border-radius: 8px;
  display: flex;
  gap: 2px;
  justify-content: space-between;
  font-size: 1.3rem;
  background: black;
  cursor: pointer;
  background: linear-gradient(180deg, #28411F 20.31%, #000 100%);
}


/* center div */

#second-brother {
  font-size: 1.8rem;
  width: 80%;
  margin: 0 auto;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  border-left: black solid 2px;
  border-right: black solid 2px;
}

.animation {
  animation-name: highlight;
  animation-duration: 1s;
  animation-iteration-count: 1;
}

@keyframes highlight {
  0% {
    box-shadow: none;
  }
  50% {
    box-shadow: 0 0px 10px 10px orange;
  }
  100% {
    box-shadow: none;
  }
}


/* center changing text  */

#second-brother::after {
  content: "2nd";
  position: relative;
}


/* outer left div */

#first-brother {
  border-radius: 8px 0px 0px 8px;
  width: 20%;
  height: 65px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 20px;
  font-size: 1.5rem;
}


/* outer left div text */

#first-brother::after {
  content: "1st";
  position: relative;
}


/* outer right div */

#third-brother {
  border-radius: 0px 8px 8px 0px;
  width: 20%;
  height: 65px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 20px;
  font-size: 1.5rem;
}

.animation2 {
  animation-name: highlight2;
  animation-delay: .5s;
  animation-duration: 1s;
  animation-iteration-count: 1;
}

@keyframes highlight2 {
  0% {
    box-shadow: none;
  }
  50% {
    box-shadow: 0 0px 10px 10px orange;
  }
  100% {
    box-shadow: none;
  }
}


/* outer right div text */

#third-brother::after {
  content: "3rd";
  position: relative;
}

@media (max-width: 625px) {
  #first-brother-left::after {
    margin-left: 12px;
  }
}

@media (max-width: 480px) {
  #countdown-right,
  #countdown-left,
  #center-battery {
    font-size: 1rem;
  }
}


/* Brothers text */

@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

#first-bro-text {
  display: block;
  animation: fadeIn .5s;
}

#second-bro-text {
  display: none;
  animation: fadeIn .5s;
}

#third-bro-text {
  display: none;
  animation: fadeIn .5s;
}

.bridge-green {
  background: linear-gradient(180deg, #4A7938 20.31%, #000 100%);
  animation: fadeIn 1s;
}
<div class="scroll-container">
  <!-- For Spacing -->
  <h1>Scroll down....<br />Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus architecto voluptatem numquam, nihil ullam suscipit, odit placeat labore natus maxime laborum aliquam voluptates animi, dicta facere debitis earum beatae nemo.
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Rem totam aut fugiat nostrum animi, sed illum ad minima sint sequi nemo, labore, suscipit et reiciendis fuga corrupti! Provident, tempore ab. Lorem ipsum dolor sit amet consectetur adipisicing
    elit. Reiciendis enim ad quos incidunt culpa necessitatibus eveniet aut earum quia, est iste debitis eos quidem facilis facere? Velit temporibus esse adipisci?</h1>

  <div class="bridge-container bridge">
    <div id="first-brother" class="bridge-green" onclick="firstBro()"></div>
    <div id="second-brother" onclick="secondBro()"></div>
    <div id="third-brother" onclick="thirdBro()"></div>
    <div id="rmg">HELLO</div>
  </div>

  <div id="first-bro-text">
    <p style="color:#225BBE;font-weight:900;">First Brother</p>
    <p>So, the oldest brother, who was a combative man, asked for a wand more powerful than any in existence. A wand that must always win battles for its owner. A wand worthy of a wizard who had conquered Death. So, Death had crossed to an Elder Tree on
      the banks of the river, fashioned a wand from a branch that had hung there, and gave it to the oldest brother</p>
  </div>
  <div id="second-bro-text">
    <p style="color:#225BBE;font-weight:900;">Second Brother</p>
    <p>Then the second brother, who was an arrogant man, decided that he wanted to humiliate Death still further, and asked for the power to recall others from Death. So, Death picked up a stone from the riverbank and gave it to the second brother, and told
      him that the stone would have the power to bring back the dead.</p>
  </div>
  <div id="third-bro-text">
    <p style="color:#225BBE;font-weight:900;">Third Brother</p>
    <p>Finally, Death turned to the third brother. A humble man, he asked for something that would enable him to go forth from that place without being followed by Death. And so it was that Death reluctantly handed over his own Cloak of Invisibility. </p>
  </div>

  <div id="click-me">Click Me</div>
  <!-- For Spacing -->
  <h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus architecto voluptatem numquam, nihil ullam suscipit, odit placeat labore natus maxime laborum aliquam voluptates animi, dicta facere debitis earum beatae nemo. Lorem ipsum dolor sit
    amet consectetur adipisicing elit. Rem totam aut fugiat nostrum animi, sed illum ad minima sint sequi nemo, labore, suscipit et reiciendis fuga corrupti! Provident, tempore ab. Lorem ipsum dolor sit amet consectetur adipisicing elit. Reiciendis enim
    ad quos incidunt culpa necessitatibus eveniet aut earum quia, est iste debitis eos quidem facilis facere? Velit temporibus esse adipisci?</h1>

</div>

我尝试在CSS中将animation-iteration-count设置为1,但是每当单击具有onClick函数的第一个、第二个或第三个元素时,动画就会重新开始。

我在相交观察元素之外添加了一个 onClick 函数,并且动画不运行,因此它必须与具有相交观察者的元素相关。

我在没有 onclick 的交集观察者中添加了一个元素(Hello 文本),并且动画不会触发,因此问题必须与具有 onclick 的元素有关。

javascript css onclick css-animations intersection-observer
1个回答
0
投票

该问题是由

animation
animation2
类与
bridge-green
类组合引起的,它们都具有动画。每当您的元素进入视图时,就会播放
highlight
动画。然后,当您单击时,您将添加
bridge-green
类并覆盖动画。再次删除
bridge-green
类将再次触发
highlight
动画。

解决方案是扩展 Intersection Observer 逻辑,仅在元素进入视图时添加

animation
类,然后停止观察。这将防止多次添加
animation
类。

然后在动画完成后使用

animationend
删除
animation
类,以便
bridge-green
可以完成它的任务,而不会受到
animation
的干扰。

function firstBro() {
  document.getElementById("first-bro-text").style.display = "block";
  document.getElementById("second-bro-text").style.display = "none";
  document.getElementById("third-bro-text").style.display = "none";
  document.getElementById("first-brother").classList.add("bridge-green");
  document.getElementById("second-brother").classList.remove("bridge-green");
  document.getElementById("third-brother").classList.remove("bridge-green");
}

function secondBro() {
  document.getElementById("first-bro-text").style.display = "none";
  document.getElementById("second-bro-text").style.display = "block";
  document.getElementById("third-bro-text").style.display = "none";
  document.getElementById("first-brother").classList.remove("bridge-green");
  document.getElementById("second-brother").classList.add("bridge-green");
  document.getElementById("third-brother").classList.remove("bridge-green");
}

function thirdBro() {
  document.getElementById("first-bro-text").style.display = "none";
  document.getElementById("second-bro-text").style.display = "none";
  document.getElementById("third-bro-text").style.display = "block";
  document.getElementById("first-brother").classList.remove("bridge-green");
  document.getElementById("second-brother").classList.remove("bridge-green");
  document.getElementById("third-brother").classList.add("bridge-green");
}

// animation
const bridge = document.querySelector('.bridge');
const secondBroEl = document.querySelector('#second-brother');
const thirdBroEl = document.querySelector('#third-brother');

const observer = new IntersectionObserver((entries, observer) => {
  for (const { isIntersecting } of entries) {
    if (isIntersecting) {
      secondBroEl.classList.add('animation');
      thirdBroEl.classList.add('animation');
      
      observer.unobserve(bridge);
    }
  }
});

observer.observe(bridge);

secondBroEl.addEventListener('animationend', removeAnimationAfterFinish);
thirdBroEl.addEventListener('animationend', removeAnimationAfterFinish);

function removeAnimationAfterFinish(event) {
  event.target.classList.remove('animation');
}
.scroll-container {
  max-width: 480px;
}


/* Bridge CSS */

.bridge-container {
  height: 65px;
  color: white;
  border-radius: 8px;
  display: flex;
  gap: 2px;
  justify-content: space-between;
  font-size: 1.3rem;
  background: black;
  cursor: pointer;
  background: linear-gradient(180deg, #28411F 20.31%, #000 100%);
}


/* center div */

#second-brother {
  font-size: 1.8rem;
  width: 80%;
  margin: 0 auto;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  border-left: black solid 2px;
  border-right: black solid 2px;
}

#second-brother.animation {
  animation-name: highlight;
  animation-duration: 1s;
}

@keyframes highlight {
  0% {
    box-shadow: none;
  }
  50% {
    box-shadow: 0 0px 10px 10px orange;
  }
  100% {
    box-shadow: none;
  }
}


/* center changing text  */

#second-brother::after {
  content: "2nd";
  position: relative;
}


/* outer left div */

#first-brother {
  border-radius: 8px 0px 0px 8px;
  width: 20%;
  height: 65px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 20px;
  font-size: 1.5rem;
}


/* outer left div text */

#first-brother::after {
  content: "1st";
  position: relative;
}


/* outer right div */

#third-brother {
  border-radius: 0px 8px 8px 0px;
  width: 20%;
  height: 65px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 20px;
  font-size: 1.5rem;
}

#third-brother.animation {
  animation-name: highlight;
  animation-delay: .5s;
  animation-duration: 1s;
}


/* outer right div text */

#third-brother::after {
  content: "3rd";
  position: relative;
}

@media (max-width: 625px) {
  #first-brother-left::after {
    margin-left: 12px;
  }
}

@media (max-width: 480px) {
  #countdown-right,
  #countdown-left,
  #center-battery {
    font-size: 1rem;
  }
}


/* Brothers text */

@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

#first-bro-text {
  display: block;
  animation: fadeIn .5s;
}

#second-bro-text {
  display: none;
  animation: fadeIn .5s;
}

#third-bro-text {
  display: none;
  animation: fadeIn .5s;
}

.bridge-green {
  background: linear-gradient(180deg, #4A7938 20.31%, #000 100%);
  animation: fadeIn 1s;
}
<div class="scroll-container">
  <!-- For Spacing -->
  <h1>Scroll down....<br />Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus architecto voluptatem numquam, nihil ullam suscipit, odit placeat labore natus maxime laborum aliquam voluptates animi, dicta facere debitis earum beatae nemo.
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Rem totam aut fugiat nostrum animi, sed illum ad minima sint sequi nemo, labore, suscipit et reiciendis fuga corrupti! Provident, tempore ab. Lorem ipsum dolor sit amet consectetur adipisicing
    elit. Reiciendis enim ad quos incidunt culpa necessitatibus eveniet aut earum quia, est iste debitis eos quidem facilis facere? Velit temporibus esse adipisci?</h1>

  <div class="bridge-container bridge">
    <div id="first-brother" class="bridge-green" onclick="firstBro()"></div>
    <div id="second-brother" onclick="secondBro()"></div>
    <div id="third-brother" onclick="thirdBro()"></div>
    <div id="rmg">HELLO</div>
  </div>

  <div id="first-bro-text">
    <p style="color:#225BBE;font-weight:900;">First Brother</p>
    <p>So, the oldest brother, who was a combative man, asked for a wand more powerful than any in existence. A wand that must always win battles for its owner. A wand worthy of a wizard who had conquered Death. So, Death had crossed to an Elder Tree on
      the banks of the river, fashioned a wand from a branch that had hung there, and gave it to the oldest brother</p>
  </div>
  <div id="second-bro-text">
    <p style="color:#225BBE;font-weight:900;">Second Brother</p>
    <p>Then the second brother, who was an arrogant man, decided that he wanted to humiliate Death still further, and asked for the power to recall others from Death. So, Death picked up a stone from the riverbank and gave it to the second brother, and told
      him that the stone would have the power to bring back the dead.</p>
  </div>
  <div id="third-bro-text">
    <p style="color:#225BBE;font-weight:900;">Third Brother</p>
    <p>Finally, Death turned to the third brother. A humble man, he asked for something that would enable him to go forth from that place without being followed by Death. And so it was that Death reluctantly handed over his own Cloak of Invisibility. </p>
  </div>

  <div id="click-me">Click Me</div>
  <!-- For Spacing -->
  <h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Temporibus architecto voluptatem numquam, nihil ullam suscipit, odit placeat labore natus maxime laborum aliquam voluptates animi, dicta facere debitis earum beatae nemo. Lorem ipsum dolor sit
    amet consectetur adipisicing elit. Rem totam aut fugiat nostrum animi, sed illum ad minima sint sequi nemo, labore, suscipit et reiciendis fuga corrupti! Provident, tempore ab. Lorem ipsum dolor sit amet consectetur adipisicing elit. Reiciendis enim
    ad quos incidunt culpa necessitatibus eveniet aut earum quia, est iste debitis eos quidem facilis facere? Velit temporibus esse adipisci?</h1>

</div>

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