如何将 class 添加到纯 javascript 中的随机元素

How to add class to random element in pure javascript

我有一个 ul,里面有一些 li。 我想随机 select 一个 li 并添加一个 .active class 1 秒,然后删除 .active class 并随机 select下一个 li

我试图在不使用 setInterval 或 Timeout 的情况下执行此操作,因此我尝试使用 requestAnimationFrame,尽管我认为我使用 javascript 的逻辑在随机化方面不太正确。

目前我可以使用它,但是每次再次调用该函数时,它 select 都是一样的 li

<ul>
  <li class="light active"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
</ul>

Javascript

(function() {

var lights = document.getElementsByClassName("light");
var random = Math.floor(Math.random() * (lights.length - 1)) + 0;
var randomLight = lights[random];

function repeatOften() {
  randomLight.classList += randomLight.classList ? ' active' : ' light';
  requestAnimationFrame(repeatOften);
}
requestAnimationFrame(repeatOften);

})();

这是一支笔:https://codepen.io/H0BB5/pen/PJjapX?editors=0010

提前致谢!

运行 未来或多或少已知时间的函数的正确选择是 setTimeoutrequestAnimationFrame 用于在不中断渲染循环的情况下应尽可能频繁地 运行 的东西,比如每秒 60 次(又名 "at 60 fps")。

在您的情况下,您的更新速度相对较慢,为每秒一次,因此 setTimeout 没有什么坏处。

您可能想要跟踪两个元素:一个是您正在更改的元素,另一个是您之前更改过的元素,以便您可以重置它。

此外,classList.toggle 会派上用场,因为它会根据 class 是否已经存在来添加或删除它。

(function() {
  var lights = document.getElementsByClassName("light");
  var previousLight = null;

  function repeatOften() {
    if (previousLight) previousLight.classList.toggle('active')

    var random = Math.floor(Math.random() * (lights.length - 1)) + 0;
    var randomLight = lights[random];
    randomLight.classList.toggle(randomLight);
    previousLight = randomLight;
    setTimeout(repeatOften, 1000);
  }

  setTimeout(repeatOften, 1000);
})();

Here 是更新后的(略有改动的)笔。

您需要更新每次函数运行时要闪烁的灯。要每秒进行不同的灯光变化,请检查动画帧时间是否为一秒。

(function repeatOften(ts) {
  if (ts % 1000 < 10) {
    document.getElementsByClassName("active")[0].classList.remove('active');
    var lights = document.getElementsByClassName("light");
    lights[Math.floor(Math.random() * lights.length)].classList.add('active');
  }
  requestAnimationFrame(repeatOften);
})();
li {
  background: 1px black
}

li.active {
  animation: blink 1s ease-in-out infinite;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}
<ul>
  <li class="light active"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
</ul>

I am trying to do this without the use of setInterval or Timeout

您可以使用 animationend 事件在当前 CSS 动画完成时调用相同的函数

function fn() {
  var lights = document.querySelectorAll(".light");
  var random = Math.floor(Math.random() * lights.length);
  var randomLight = lights[random];
  repeatOften(randomLight)
};

function repeatOften(randomLight) {
  randomLight.className = "light active";
  randomLight.addEventListener("animationend", blink)
}

function blink() {
  this.className = "light";
  this.removeEventListener("animationend", blink);
  fn();
}

// handle first `li`
document.querySelector(".light.active")
.addEventListener("animationend", blink)
.light.active {
  animation: blink 1s ease-in-out;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}
<ul>
  <li class="light active"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
  <li class="light"></li>
</ul>