如何强制元素的 CSS 动画从与上一个动画完成的位置相同的位置开始?

Posted

技术标签:

【中文标题】如何强制元素的 CSS 动画从与上一个动画完成的位置相同的位置开始?【英文标题】:How can I force a CSS animation of an element to start from the same location as the previous animation finished? 【发布时间】:2022-01-05 10:35:13 【问题描述】:

我有一个图像,我想在每次单击鼠标时移动一定距离(始终相同)和特定方向(在数组中指定)。第一次单击将其移动到第一个数组元素中指定的方向,第二次单击第二个,依此类推。

除非我要求它连续两次向同一方向移动,否则这很好用。在这种情况下,它会立即移动到没有动画的结束位置,就好像它已经在那里开始了动画一样,尽管调试器显示了由 unitElement.style.left 定义的位置,与它在屏幕上的外观正确对应。

html,带有四个转换和一个要移动的图像:

<style>
    .unit  width: 60px; height: 60px; position: absolute; 

    @keyframes N 100% transform: translate(0px, -60px);
    @keyframes E 100% transform: translate(60px, 0px);
    @keyframes S 100% transform: translate(0px, 60px);
    @keyframes W 100% transform: translate(-60px, 0px);
</style>

<body>
    <img src="test.png" class="unit" id="F1" />
</body>

点击事件调用的函数:

function nextPulseAnimate() 
    pulse++;
    for(var index = 0; index < units.length; index++) 
    
        var unit = units[index];
        var direction = unit.moves[pulse-1]
        
        var unitElement = document.getElementById(unit.name);

        //ensure that the image is starting from the right place
        unitElement.style.left = unit.start.x;
        unitElement.style.top = unit.start.y;

        unitElement.style.animation = direction + " 2s ease-in-out forwards";
    

    //then re-set the locations ready for next pulse
    //If this is not done, each animation will start from the unit's original location
    for(var index = 0; index < units.length; index++) 
        var unit = units[index];
        var direction = unit.moves[pulse-1]
            
        switch (direction)
         case "N":
             unit.start.y -= 60; 
             break;
         case "E": 
             unit.start.x += 60;
             break;
         case "S":
             unit.start.y += 60;
             break; 
         case "W": 
             unit.start.x -= 60;
             break;
         
    

函数中提到的“单元”来自一个全局对象数组,看起来像这样(实际上它会有几十个元素):

units = [
    name: "F1", start: x: 0, y: 0, moves: ["S", "E", "E", "E"]
];

为了完整起见,定义了另一个全局变量(并在上面使用): 脉冲 = 0

【问题讨论】:

提供 css .unit 规则定义。如何。您的 img 是静态的、相对的、绝对的还是固定的?一个最小的可重现代码会非常好。 当然。这是 .unit 的 css 定义: .unit width: 60px;高度:60px;位置:绝对; 我的意思是像.unit position: absolute; height:20px这样的整个css规则。更新你的开场白/问题 在第二个 for 循环中,您将单位设置为固定坐标,它们实际上并不是它们的最后位置。有一个 DOM 事件 onAnimationEnd 您可以使用它来更新最后一个坐标。 developer.mozilla.org/en-US/docs/Web/API/HTMLElement/… 连续两次问题:当你设置相同的动画名称时,系统不会动画,因为它认为它已经完成了。您需要清除它并以某种方式重置。 【参考方案1】:

这就是我的意思:

units = [name: "F1", start:  x: '0px', y: '0px',
    moves: ["S", "E", "E", "N", "W", "W"]
  ,
   name: "F2", start:  x: '120px', y: '60px' ,
    moves: ["N", "W", "W", "S", "E", "E"]
  
];

var pulse = 0;

function init() 
  document.body.addEventListener("click", nextPulseAnimate);

  for (var index = 0; index < units.length; index++) 
    var unit = units[index];
    var unitElement = document.getElementById(unit.name);
    unitElement.style.left = unit.start.x;
    unitElement.style.top = unit.start.y;

    unitElement.addEventListener('animationend', (event) => 
      document.body.addEventListener("click", nextPulseAnimate);
      var e = event.target;
      /* get position relative to viewport */
      var r = e.getBoundingClientRect();
      e.style.left = r.left + 'px';
      e.style.top = r.top + 'px';
      /* remove animation so that you can use it again */
      e.style.animation = 'none';
    );
  


function nextPulseAnimate() 
  pulse++;
  if (pulse < 7) 
    document.getElementById('stats').innerText = 'Moves: ' + pulse + '/6';
    //don't let user click while animation is going on
    document.body.removeEventListener('click', nextPulseAnimate);
  

  for (var index = 0; index < units.length; index++) 
    var unit = units[index];
    var direction = unit.moves[pulse - 1]
    var unitElement = document.getElementById(unit.name);
    unitElement.style.animation = direction + " 2s ease-in-out forwards";
  
body 
  width: 90vw;
  height: 90vh


p 
  position: fixed;
  top: 40vh;


.unit  width: 60px; height: 60px; position: absolute; 

@keyframes N 100% transform: translate(0px, -60px);
@keyframes E 100% transform: translate(60px, 0px);
@keyframes S 100% transform: translate(0px, 60px);
@keyframes W 100% transform: translate(-60px, 0px);
<!DOCTYPE html>
<html>

<body onload="init()">
  <img src="https://dummyimage.com/60x60/000/fff.jpg" class="unit" id="F1" />
  <img src="https://dummyimage.com/60x60/a0a/fff.jpg" class="unit" id="F2" />
  <p id=stats>Click anywhere to trigger moves</p>
</body>

</html>

【讨论】:

以上是关于如何强制元素的 CSS 动画从与上一个动画完成的位置相同的位置开始?的主要内容,如果未能解决你的问题,请参考以下文章

css3 动画:悬停;强制整个动画

java - 如何在java脚本或css中完成动画后使元素可拖动?

您可以使用 JavaScript 将 CSS 关键帧动画“强制”到其最终状态吗?

将元素的属性强制为某个值,即使它正在被动画化

当使用 css3 缩放元素时,它会变成像素化,直到动画完成之后。我正在为带有边框的元素制作动画

如何跨多个元素同步 CSS 动画?