【问题标题】:@keyframes animation works only the first time@keyframes 动画只在第一次工作
【发布时间】:2021-04-21 16:56:40
【问题描述】:

我在选择中有 3 个值:石头、纸、剪刀。

当我第一次在选择中选择一个值(石头、纸或剪刀)时,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>

【问题讨论】:

    标签: javascript css css-animations onchange css-transforms


    【解决方案1】:

    这是因为您在第一个选择中添加了一次内联动画,然后从不删除它,因此它再也不会被调用。不重构所有内容的最简单方法是使用animationend 事件在动画之后删除内联样式,或者甚至使用延迟比动画长的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 的元素、节点列表(或其他任何东西),您应该考虑将其存储在一个变量中。您可以将其存储为变量,并在最后调用一次函数(如 innerText),而不是在同一个 if/else 块中多次解析 DOM。

    如果您需要进行更改,这有助于避免在多个位置更新引用。

    最后,您可能更适合将关键帧动画附加到一个类,并使用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>

    文档和函数参考

    【讨论】:

    • 感谢您的解释、参考和清理我的代码! :)
    【解决方案2】:

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

    在您的获胜者()函数的末尾添加以下代码:

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

    【讨论】:

      【解决方案3】:

      当您第一次选择 select onchange 事件中的值并添加动画样式时。 (永久添加到 dom 中)

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

      添加.animateonchange

      CSS:

      .animate {
        animation: example 0.5s alternate;
      }
      

      JS:

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

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

      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>

      【讨论】:

      • 如果我连续两次选择一个值,这将不起作用。 (2 次石头、纸或剪刀)
      【解决方案4】:

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

      更改下面的行

      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)
      

      这里的settimeout延迟时间是基于动画时长

      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>

      【讨论】:

        猜你喜欢
        • 2016-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-03
        相关资源
        最近更新 更多