无缝播放新的 css 动画

Play new css animation seamlessly

我创建了一个简单的 HTML 游戏,当我点击一个移动的方块时它会在屏幕下方消失。 但是,消失的动画从原始位置开始,而不是单击的位置。

我觉得0%的remove @keyframes应该有点击的位置,但是找不到方法

我该怎么办?

  (function () {
    const charactersGroup = document.querySelectorAll('.character');
    const stage = document.querySelector('.stage')
    const clickHandler = (e) => {
      const target = e.target;
      if (target.classList.contains('character')) {
        target.classList.remove(`f${target.dataset.id}`);
        target.classList.add('f0');
        target.classList.add('remove');

        setTimeout(() => { stage.removeChild(target) }, 2000);
      }
    }
    stage.addEventListener('click', clickHandler);
  }());
.stage {
      overflow: hidden;
      position: relative;
      background: #eeeeaa;
      width: 40vw;
      height: 20vw;
    }

    @keyframes moving {
      0% {
        transform: translateX(0);
      }
      100% {
        transform: translateX(30vw);
      }
    }
    @keyframes remove {
      0% {
        transform: translate(0);
      }
      100% {
        transform: translateY(60vw);
      }
    }
    .character {
      position: absolute;
      width: 50px;
      height: 50px;
      background-repeat: no-repeat;
      background-position: 50% 50%;
      background-size: contain;
      animation: moving infinite alternate;
    }
    .remove {
      animation: remove 0.2s cubic-bezier(.68,-0.55,.27,1.55) forwards;
    }
    .f0 {
      background-color: black;
      animation-duration: 2s;
    }
    .f1 {
      left: 5%;
      bottom: 5%;
      animation-duration: 2s;
      background-color: red;
    }
<div class="stage">
  <div class="character f1" data-id="1"></div>
</div>

如果您的用例是处理很多这样的框和复杂性,最好使用纯 JS 处理所有内容,但我试图通过对 JS 和 CSS 的最小更改来完成这项工作。

我已经为新的 JS 行添加了注释。

还冒昧地为动画 moving 单独设置了一个名为 moving 的 class,以便我们可以在单击时将其删除。

(function () {
    const charactersGroup = document.querySelectorAll('.character');
    const stage = document.querySelector('.stage')
    const clickHandler = (e) => {
      const target = e.target;
      if (target.classList.contains('character')) {
        target.classList.remove(`f${target.dataset.id}`);
        target.classList.add('f0');
        // remove the moving animation
        target.classList.remove('moving');
        // Get offsetWidth which is the half of width to substract later while calculating left for the target i.e our box.
        const offsetWidth  = parseInt(getComputedStyle(target).width)/2;
        // e.clientX gives us the x coordinate of the mouse pointer
        // target.getBoundingClientRect().left gives us left position of the bounding rectangle and acts as a good offset to get the accurate left for our box.
        target.style.left = `${e.clientX -target.getBoundingClientRect().left - offsetWidth}px`;
       target.classList.add('remove');
     setTimeout(() => { stage.removeChild(target) }, 2000);
      } 
    }
    stage.addEventListener('click', clickHandler);
  }());
.stage {
      overflow: hidden;
      position: relative;
      background: #eeeeaa;
      width: 40vw;
      height: 20vw;
    }

    @keyframes moving {
      0% {
        transform: translateX(0);
      }
      100% {
        transform: translateX(30vw);
      }
    }
    @keyframes remove {
      0% {
        transform: translate(0vh);
      }
      100% {
        transform: translateY(60vw);
      }
    }
    .character {
      position: absolute;
      width: 50px;
      height: 50px;
      background-repeat: no-repeat;
      background-position: 50% 50%;
      background-size: contain;
    }
    
    .moving{
      animation: moving infinite alternate;
    }
    .remove {
      animation: remove 0.2s cubic-bezier(.68,-0.55,.27,1.55) forwards;
    }
    .f0 {
      background-color: black;
      animation-duration: 2s;
    }
    .f1 {
      left: 5%;
      bottom: 5%;
      animation-duration: 2s;
      background-color: red;
    }
<div class="stage">
  <div class="character moving f1" data-id="1"></div>
</div>

更改第一个动画以考虑 left 而不是翻译,然后将它们都附加到最初的元素,您只需在添加 remove [=24= 时切换 animation-play-state ]

(function() {
  const charactersGroup = document.querySelectorAll('.character');
  const stage = document.querySelector('.stage')
  const clickHandler = (e) => {
    const target = e.target;
    if (target.classList.contains('character')) {
      target.classList.add('remove');

      setTimeout(() => {
        stage.removeChild(target)
      }, 2000);
    }
  }
  stage.addEventListener('click', clickHandler);
}());
.stage {
  overflow: hidden;
  position: relative;
  background: #eeeeaa;
  width: 40vw;
  height: 20vw;
}

@keyframes moving {
  100% {
    left:calc(95% - 50px);
  }
}

@keyframes remove {
  50% {
    transform: translateY(-30vh);
  }
  100% {
    transform: translateY(60vw);
  }
}

.character {
  position: absolute;
  width: 50px;
  height: 50px;
  background:red;
  left: 5%;
  bottom: 5%;
  animation: 
     moving 2s infinite alternate,
     remove 1s cubic-bezier(.68, -0.55, .27, 1.55) forwards paused;
}

.remove {
  animation-play-state:paused,running;
  background: black;
}
<div class="stage">
  <div class="character f1" data-id="1"></div>
</div>