【问题标题】:Why animation don't complete its path when duration is decreased by JavaScript为什么当 JavaScript 减少持续时间时动画没有完成它的路径
【发布时间】:2021-12-23 00:44:55
【问题描述】:

我有一个动画,其 duration 每次 black 跳跃(使用空间)越过 red 时都会减少,随后的跳跃会减少 duration 的效果很好。

但是在一定的时间减少之后,比如说在减少到4s,3.9s,3.8s...之后,动画不会从应该是的最右边开始。在@keyframes animateVillan中决定路径(110vw)

是不是我做错了什么,首先认为这是一种故障类型,并决定仅在 red 达到小于 10 并尝试以下部分时才更改持续时间

if (ourVillanFigXValue < 10) {
      ourVillanFig.style.animationDuration = ourVillanAnimeDuration - 0.1 + "s";
    }

但这并没有解决问题,并且路径没有完全被红色

不好意思要跳一点,跳四五下才看到错误plz

let ourHeroFig = document.getElementById("ourHero");
let ourVillanFig = document.getElementById("obstacleBar");
let gameScoreDigits = document.getElementById("gameScoreDigits");
let valueXCoordinate = "";
let obstacleBarCrossed = true;

document.body.addEventListener('keydown', function(e) {
  let ourHeroFigXValue = parseInt(getComputedStyle(ourHeroFig).getPropertyValue('left'));
  let ourHeroFigYValue = parseInt(getComputedStyle(ourHeroFig).getPropertyValue('bottom'));

  if (e.code === "ArrowRight") {
    valueXCoordinate = ourHeroFigXValue + 100;

  } else if (e.code === "KeyA" || e.code === "ArrowLeft") {
    if (ourHeroFigXValue > ourHeroFig.offsetWidth + 90) {
      valueXCoordinate = ourHeroFigXValue - 100;
    } else {
      valueXCoordinate = 0;
    }
  } else if (e.code === "Space") {
    ourHeroFig.classList.add("animateHero");
    setTimeout(function() {
      ourHeroFig.classList.remove("animateHero");
    }, 700)
  }
  changePosition();

})

function changePosition() {
  ourHeroFig.style.left = valueXCoordinate + 'px'
}

let delayInAnimeSub = ""
setInterval(
  function() {
    let ourHeroFigXValue = parseInt(getComputedStyle(ourHeroFig).getPropertyValue('left'));
    let ourHeroFigYValue = parseInt(getComputedStyle(ourHeroFig).getPropertyValue('bottom'));
    let ourVillanFigXValue = parseInt(getComputedStyle(ourVillanFig).getPropertyValue('left'));
    let ourVillanFigYValue = parseInt(getComputedStyle(ourVillanFig).getPropertyValue('bottom'));
    let gameOverValueX = Math.abs(ourVillanFigXValue - ourHeroFigXValue);
    let gameOverValueY = Math.abs(ourVillanFigYValue - ourHeroFigYValue);

    if (ourVillanFigXValue < 10) {
      ourVillanFig.style.animationDuration = ourVillanAnimeDuration - 0.3 + "s";
    }
    if (gameOverValueX < ourVillanFig.offsetWidth && gameOverValueY < ourVillanFig.offsetHeight) {
      console.log("yes touched");
      ourVillanFig.classList.remove("animateVillan");
      obstacleBarCrossed = false;
    } else if (obstacleBarCrossed && gameOverValueX < ourVillanFig.offsetWidth) {
      ourVillanAnimeDuration = parseFloat(getComputedStyle(ourVillanFig).getPropertyValue('animation-duration'));
      console.log(ourVillanFigXValue < 0, ourVillanAnimeDuration)

      if (ourVillanAnimeDuration <= 2) {
        ourVillanAnimeDuration = 2
      }
    }
    // console.log(gameOverValueX,gameOverValueY)
  }, 10);
#ourHero {
  width: 20px;
  height: 180px;
  background-color: black;
  position: fixed;
  bottom: 0;
  left: 0;
  transition: 0.1s;
}

.animateHero {
  animation: animateHero 0.7s linear;
}

@keyframes animateHero {
  0% {
    bottom: 0;
  }
  50% {
    bottom: 350px;
  }
  100% {
    bottom: 0;
  }
}

#obstacleBar {
  width: 20px;
  height: 180px;
  background-color: red;
  position: fixed;
  bottom: 0;
  left: 50vw;
}

.animateVillan {
  animation: animateVillan 5s linear infinite;
}

@keyframes animateVillan {
  0% {
    left: 110vw;
  }
  100% {
    left: 0;
  }
}
<div id="ourHero"></div>
<div id="obstacleBar" class="animateVillan"></div>

提前感谢您的帮助

【问题讨论】:

    标签: javascript html css animation


    【解决方案1】:

    首先让红色的东西从最右边开始,所以将left: 50vw; 更改为left: 110vw;。另外,不是无限动画,而是在红色离开屏幕后删除animateVillan 类,然后重新添加它。可以通过使用animationend 事件处理程序来完成:

    ourVillanFig.addEventListener('animationend', () => {
      ourVillanFig.classList.remove('animateVillan')
      ourVillanFig.clientHeight // just to cause a reflow
      ourVillanFig.classList.add('animateVillan')
    })
    

    或者也许通过检查它的 x 位置,看看它什么时候出来。

    这是结果。看起来它工作得很好,没有任何故障:

    编辑:要使红色在接触黑色时停止,您可以创建以下 css 类:

    .pauseVillan {
          animation-play-state: paused;
        }
    

    然后当红色取得联系时,只需将pauseVillan 类添加到它:

    ourVillanFig.classList.add('pauseVillan')
    

    这里是更新的sn-p:

    let ourHeroFig = document.getElementById('ourHero')
    let ourVillanFig = document.getElementById('obstacleBar')
    let gameScoreDigits = document.getElementById('gameScoreDigits')
    let valueXCoordinate = ''
    let obstacleBarCrossed = true
    
    document.body.addEventListener('keydown', function(e) {
      let ourHeroFigXValue = parseInt(
        getComputedStyle(ourHeroFig).getPropertyValue('left')
      )
      let ourHeroFigYValue = parseInt(
        getComputedStyle(ourHeroFig).getPropertyValue('bottom')
      )
    
      if (e.code === 'ArrowRight') {
        valueXCoordinate = ourHeroFigXValue + 100
      } else if (e.code === 'KeyA' || e.code === 'ArrowLeft') {
        if (ourHeroFigXValue > ourHeroFig.offsetWidth + 90) {
          valueXCoordinate = ourHeroFigXValue - 100
        } else {
          valueXCoordinate = 0
        }
      } else if (e.code === 'Space') {
        ourHeroFig.classList.add('animateHero')
        setTimeout(function() {
          ourHeroFig.classList.remove('animateHero')
        }, 700)
      }
      changePosition()
    })
    
    ourVillanFig.addEventListener('animationend', () => {
      ourVillanFig.classList.remove('animateVillan')
      ourVillanFig.clientHeight // just to cause a reflow
      ourVillanFig.classList.add('animateVillan')
    })
    
    function changePosition() {
      ourHeroFig.style.left = valueXCoordinate + 'px'
    }
    
    let delayInAnimeSub = ''
    setInterval(function() {
      let ourHeroFigXValue = parseInt(
        getComputedStyle(ourHeroFig).getPropertyValue('left')
      )
      let ourHeroFigYValue = parseInt(
        getComputedStyle(ourHeroFig).getPropertyValue('bottom')
      )
      let ourVillanFigXValue = parseInt(
        getComputedStyle(ourVillanFig).getPropertyValue('left')
      )
      let ourVillanFigYValue = parseInt(
        getComputedStyle(ourVillanFig).getPropertyValue('bottom')
      )
      let gameOverValueX = Math.abs(ourVillanFigXValue - ourHeroFigXValue)
      let gameOverValueY = Math.abs(ourVillanFigYValue - ourHeroFigYValue)
    
      if (ourVillanFigXValue < 10) {
        ourVillanFig.style.animationDuration =
          ourVillanAnimeDuration - 0.3 + 's'
      }
      if (
        gameOverValueX < ourVillanFig.offsetWidth &&
        gameOverValueY < ourVillanFig.offsetHeight
      ) {
        console.log('yes touched')
        ourVillanFig.classList.add('pauseVillan')
        obstacleBarCrossed = false
      } else if (
        obstacleBarCrossed &&
        gameOverValueX < ourVillanFig.offsetWidth
      ) {
        ourVillanAnimeDuration = parseFloat(
          getComputedStyle(ourVillanFig).getPropertyValue('animation-duration')
        )
        console.log(ourVillanFigXValue < 0, ourVillanAnimeDuration)
    
        if (ourVillanAnimeDuration <= 2) {
          ourVillanAnimeDuration = 2
        }
      }
      // console.log(gameOverValueX,gameOverValueY)
    }, 10)
    #ourHero {
      width: 20px;
      height: 180px;
      background-color: black;
      position: fixed;
      bottom: 0;
      left: 0;
      transition: 0.1s;
    }
    
    .animateHero {
      animation: animateHero 0.7s linear;
    }
    
    @keyframes animateHero {
      0% {
        bottom: 0;
      }
      50% {
        bottom: 350px;
      }
      100% {
        bottom: 0;
      }
    }
    
    #obstacleBar {
      width: 20px;
      height: 180px;
      background-color: red;
      position: fixed;
      bottom: 0;
      left: 110vw;
    }
    
    .animateVillan {
      animation: animateVillan 4s linear;
    }
    
    .pauseVillan {
      animation-play-state: paused;
    }
    
    @keyframes animateVillan {
      0% {
        left: 110vw;
      }
      100% {
        left: 0;
      }
    }
    <div id="ourHero"></div>
    <div id="obstacleBar" class="animateVillan"></div>

    【讨论】:

    • 很好的解决方案(+1),有没有办法让 red 停留在它接触 black 的相同位置
    • @Rana 是的,通过添加一个简单的 css 类来暂停动画。查看更新的答案。
    • 非常感谢您的回答,这对您有很大帮助。
    • 你能告诉你代码中这部分ourVillanFig.clientHeight,你为什么使用它。以及为什么我的代码不能正常工作,如果这可以告诉你
    • @Rana 没有ourVillanFig.clientHeight 重新添加的动画可能不会显示,所以它只是重新启动动画。还有更多导致回流的方法,您可以找到它here。还有here 是关于重新启动动画的更多信息。
    猜你喜欢
    • 2019-07-20
    • 1970-01-01
    • 2021-01-17
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 2015-06-20
    • 2017-12-14
    相关资源
    最近更新 更多