@keyframes 动画只在第一次有效

@keyframes animation works only the first time

我在 select 中有 3 个值:石头、布、剪刀。

我第一次在 select(石头、布或剪刀)中选择一个值时,将触发 onChange 事件,@keyframes 动画适用于所有 3 个值。

但是我第二次选择任何值时,动画不再有效。 我不明白为什么。

代码是这样的: jsfiddle.net/9efvxph3/83/

body {
  background: radial-gradient(gold, goldenrod);
  font-family: monospace;
  text-align: center;
  font-size: 1.5rem;
}

@keyframes example {
  0% {
    transform: scale(1);
  }

  100% {
    transform: scale(1.3);
  }
}


img {
  padding: 10px;
  height: 100px;
  width: auto;
}

img:hover {
  transform: scale(1.4);
  transition: all 1s;
}
          <select id="choice" onchange="winner()">
            <option value="" disabled selected>choose</option>
            <option value="rock">rock</option>
            <option value="paper">paper</option>
            <option value="scissors">scissors</option>
          </select>

          <img src="https://img.icons8.com/windows/2x/hand-rock.png" class="user-choice">
          <img src="https://img.icons8.com/wired/2x/paper.png" class="user-choice">
          <img src="https://img.icons8.com/ios/2x/hand-scissors.png" class="user-choice">

          <h3 id="result"> </h3>

          <script>
            const type = ["paper", "scissors", "rock"];

            function winner() {
              var index = document.getElementById("choice").selectedIndex;

              var userChooice = document.getElementById("choice").value;
              var PcChooice = type[Math.floor(Math.random() * type.length)];

              document.getElementsByClassName("user-choice").item(index - 1).style = "animation:example 0.5s alternate";

              if (PcChooice == userChooice) {

                document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You tied";

              } else {
                if ((userChooice == "rock") && (PcChooice == "scissors")) {
                  document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You win";
                } else if ((userChooice == "paper") && (PcChooice == "rock")) {
                  document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You win";
                } else if ((userChooice == "scissors") && (PcChooice == "paper")) {
                  document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You win";
                } else {
                  document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You loose";
                }
              }
              document.getElementById("choice").selectedIndex = 0;
            };

          </script>

根据您的代码,最好通过添加与动画结束相关的事件侦听器来结束您的函数,从元素的样式中删除动画。

在 winner() 函数的末尾添加以下代码:

document.getElementsByClassName("user-choice").item(index - 1).addEventListener("animationend", function(e) {
  e.target.style = "";
});

这是因为您在第一个选择中添加了一次内联动画,然后再也没有删除它,所以它再也不会被调用。无需重构所有内容的最简单方法是使用 animationend event, or even using something like setTimeout() 延迟比动画更长的时间来删除动画后的内联样式。

添加动画后只需在某处添加以下内容即可:

document.getElementsByClassName("user-choice").item(index - 1).addEventListener("animationend", function(evt){
    evt.target.style = "";
});

或者,不太优雅:

setTimeout(function(){
    document.getElementsByClassName("user-choice").item(index - 1).style = "";
}.bind(index), 510 );

这应该是您“解决问题”所需的全部内容,但查看可读性也可能有所帮助。

为了更清楚一点——通常如果你请求一个元素,节点列表,(或任何真正的)不是 static property, you should consider storing it in a variable. Instead of parsing the DOM multiple times for the same thing in the same if/else blocks, you can store it as a variable, and invoke a function (like innerText) 最后一次。

这有助于避免在需要进行更改时需要在多个地方更新引用。

最后,您可能更适合将关键帧动画附加到 class,并且 adding/removing 将 class 附加到 classList

const type    = ["paper", "scissors", "rock"],
      result  = document.getElementById('result'),
      choice  = document.getElementById('choice'),
      choices = document.getElementsByClassName('user-choice');

function winner(){
    // Prevent changes while the game is "running"
    choice.disabled = true;

    var userChoice = choice.value,
        pcChoice   = type[Math.floor(Math.random() * type.length)],
        selected   = choices[choice.selectedIndex-1];
        status;
    
    if( pcChoice == userChoice ){
        status = 'tied';
    } else {
        if( userChoice == 'rock' && pcChoice == 'scissors' ){
            status = 'win';
        } else if( userChoice == 'paper' && pcChoice == 'rock' ){
            status = 'win';
        } else if( userChoice == 'scissors' && pcChoice == 'paper' ){
            status = 'win';
        } else {
            status = 'lose';
        }
    }

    selected.classList.add('animated');        
    result.innerText = userChoice + ' - ' + pcChoice + ': You ' + status;

    // After the animation, reset everything to its default state
    selected.addEventListener('animationend', function(evt){
        choice.disabled = false;
        choice.selectedIndex = 0;
        evt.target.classList.remove('animated');
    });
};
body {
  background: radial-gradient(gold, goldenrod);
  font-family: monospace;
  text-align: center;
  font-size: 1.5rem;
}

@keyframes example {
  0% { transform: scale(1); }
  100% { transform: scale(1.3); }
}


img {
  padding: 10px;
  height: 100px;
  width: auto;
}

img:hover {
  transform: scale(1.4);
  transition: all 1s;
}

img.animated {
  animation: example 0.5s alternate;
}
<select id="choice" onchange="winner()">
  <option value="" disabled selected>choose</option>
  <option value="rock">rock</option>
  <option value="paper">paper</option>
  <option value="scissors">scissors</option>
</select>

<img src="https://img.icons8.com/windows/2x/hand-rock.png" class="user-choice">
<img src="https://img.icons8.com/wired/2x/paper.png" class="user-choice">
<img src="https://img.icons8.com/ios/2x/hand-scissors.png" class="user-choice">

<h3 id="result"> </h3>


文档和函数参考

第一次在 select onchange 事件中选择值时会触发并添加动画样式。 (永久添加在dom)

第二次选择任何值时,onchange 事件将触发,但动画将不起作用因为它已经存在于 dom.

添加.animateclassonchange.

CSS:

.animate {
  animation: example 0.5s alternate;
}

JS:

document.getElementsByClassName("user-choice").item(index - 1).classList.add('animate');

在添加 .animate class 之前从所有 .user-choice 元素中删除 .animate class。

var choicess = document.getElementsByClassName("user-choice");
[].forEach.call(choicess, function(el) {
  el.classList.remove('animate');
});

body {
  background: radial-gradient(gold, goldenrod);
  font-family: monospace;
  text-align: center;
  font-size: 1.5rem;
}

.animate {
  animation: example 0.5s alternate;
}

@keyframes example {
  0% {
    transform: scale(1);
  }
  100% {
    transform: scale(1.3);
  }
}

img {
  padding: 10px;
  height: 100px;
  width: auto;
}

img:hover {
  transform: scale(1.4);
  transition: all 1s;
}
<select id="choice" onchange="winner()">
  <option value="" disabled selected>choose</option>
  <option value="rock">rock</option>
  <option value="paper">paper</option>
  <option value="scissors">scissors</option>
</select>

<img src="https://img.icons8.com/windows/2x/hand-rock.png" class="user-choice">
<img src="https://img.icons8.com/wired/2x/paper.png" class="user-choice">
<img src="https://img.icons8.com/ios/2x/hand-scissors.png" class="user-choice">

<h3 id="result"> </h3>

<script>
  const type = ["paper", "scissors", "rock"];

  function winner() {
    var index = document.getElementById("choice").selectedIndex;

    var userChooice = document.getElementById("choice").value;
    var PcChooice = type[Math.floor(Math.random() * type.length)];

    var choicess = document.getElementsByClassName("user-choice");
    [].forEach.call(choicess, function(el) {
      el.classList.remove('animate');
    });

    document.getElementsByClassName("user-choice").item(index - 1).classList.add('animate');

    if (PcChooice == userChooice) {

      document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You tied";

    } else {
      if ((userChooice == "rock") && (PcChooice == "scissors")) {
        document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You win";
      } else if ((userChooice == "paper") && (PcChooice == "rock")) {
        document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You win";
      } else if ((userChooice == "scissors") && (PcChooice == "paper")) {
        document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You win";
      } else {
        document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You loose";
      }
    }
    document.getElementById("choice").selectedIndex = 0;
  };
</script>

您可以通过添加和删除类名而不是直接更新元素样式来简单地修复它。

更改以下行

document.getElementsByClassName("user-choice").item(index - 1).style = "animation:example 0.5s alternate";

document.getElementsByClassName("user-choice").item(index - 1).classList.add('animate');
          
setTimeout(() => {
    document.getElementsByClassName("user-choice").item(index - 1).classList.remove('animate');
}, 1000)

其中setimeout延迟时间是根据动画时长计算的

body {
  background: radial-gradient(gold, goldenrod);
  font-family: monospace;
  text-align: center;
  font-size: 1.5rem;
}

@keyframes example {
  0% {
    transform: scale(1);
  }

  100% {
    transform: scale(1.3);
  }
}


img {
  padding: 10px;
  height: 100px;
  width: auto;
}

img:hover {
  transform: scale(1.4);
  transition: all 1s;
}

.animate {
  animation: example 0.5s alternate;
}
<select id="choice" onchange="winner()">
            <option value="" disabled selected>choose</option>
            <option value="rock">rock</option>
            <option value="paper">paper</option>
            <option value="scissors">scissors</option>
          </select>

          <img src="https://img.icons8.com/windows/2x/hand-rock.png" class="user-choice">
          <img src="https://img.icons8.com/wired/2x/paper.png" class="user-choice">
          <img src="https://img.icons8.com/ios/2x/hand-scissors.png" class="user-choice">

          <h3 id="result"> </h3>

          <script>
            const type = ["paper", "scissors", "rock"];

            function winner() {
              var index = document.getElementById("choice").selectedIndex;

              var userChooice = document.getElementById("choice").value;
              var PcChooice = type[Math.floor(Math.random() * type.length)];

              document.getElementsByClassName("user-choice").item(index - 1).classList.add('animate');
              
              setTimeout(() => {
                document.getElementsByClassName("user-choice").item(index - 1).classList.remove('animate');
              }, 1000)

              if (PcChooice == userChooice) {

                document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You tied";

              } else {
                if ((userChooice == "rock") && (PcChooice == "scissors")) {
                  document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You win";
                } else if ((userChooice == "paper") && (PcChooice == "rock")) {
                  document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You win";
                } else if ((userChooice == "scissors") && (PcChooice == "paper")) {
                  document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You win";
                } else {
                  document.getElementById("result").innerHTML = userChooice + " - " + PcChooice + ": You loose";
                }
              }
              document.getElementById("choice").selectedIndex = 0;
            };

          </script>