如何以编程方式在 CSS 动画中堆叠关键帧

How to stack keyframes in CSS animation programmatically

我正在尝试在下面堆叠 CSS 个关键帧(动画延迟),但我不确定如何以编程方式执行此操作?

        .r1 {
          animation-name: move1;
          animation-delay: 0.5s;      
          animation-duration: 1s;
          animation-iteration-count: 1;
          animation-timing-function: ease-in;
          animation-direction: normal;
          animation-fill-mode: forwards;
        }
 
        .r2 {
          animation-name: move1;
          animation-delay: 1.5s;      
          animation-duration: 1s;
          animation-iteration-count: 1;
          animation-timing-function: ease-in;
          animation-direction: normal;
          animation-fill-mode: forwards;
        }
             .r3 {
          animation-name: move1;
          animation-delay: 2.5s;      
          animation-duration: 1s;
          animation-iteration-count: 1;
          animation-timing-function: ease-in;
          animation-direction: normal;
          animation-fill-mode: forwards;
        }
 
        @keyframes move1 {
          to {
            transform: translateX(200px);
          }  
        }
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="r1" x="10" y="20" width="100" height="100" fill="red"/>
    <rect class="r2" x="10" y="130" width="100" height="100" fill="green"/>
    <rect class="r3" x="10" y="240" width="100" height="100" fill="blue"/>
</svg>

animation-duration 为每个 class 硬编码,animation-delay 为第一个 class 硬编码,即 r1.

如何传递r2和r3的延迟,例如

r2 delay= r1 delay + r1 duration->0.5+1=1.5s

r3 delay= r2 delay + r2 duration ->1.5+1=2.5s

javascript 中有什么东西可以通过 class 给出 animation-duration 吗?

我尝试通过 Element.getAnimations() 执行此操作,但我不确定是否有任何东西可以通过 class 提供动画持续时间。

我不想手动执行此操作,因为 svg 中有很多 class。

提前致谢。

为您的直肠设置 r class,我认为这可以帮助您:

const blocks = document.querySelectorAll('svg rect');

for (let i = 1; i<blocks.length; i++) {
    const element = blocks[i];
  const prevElementStyles = getComputedStyle(blocks[i-1]);

  
  element.style.animationDelay = `${parseFloat(prevElementStyles.animationDelay) + parseFloat(prevElementStyles.animationDuration)}s`;
}

r class:

.r {
  animation-name: move1;
  animation-delay: 0.5s;      
  animation-duration: 1s;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
  animation-direction: normal;
  animation-fill-mode: forwards;
}

<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="r" x="10" y="20" width="100" height="100" fill="red"/>
    <rect class="r" x="10" y="130" width="100" height="100" fill="green"/>
    <rect class="r" x="10" y="240" width="100" height="100" fill="blue"/>
</svg>

动画链接:使用事件animationend

您可以通过对此事件使用侦听器来链接 CSS 动画。当元素上的动画完成时(包括动画延迟),它将被触发。或者,如果您使用 transitions,则需要使用 transitionend 事件。

基本工作流程

将动画属性提取到单独的 class,例如.animation.

#firstEl.animation {
  // your animation properties
}
#secondEl.animation {
  // your animation properties
}
// etc
const firstEl = document.getElementById('#firstEl');
const secondEl = document.getElementById('#secondEl');
const thirdEl = document.getElementById('#thirdEl');

firstEl.classList.add('animation');
firstEl.addEventListener('animationend', () => {
  // start the 2nd animation
  secondEl.classList.add('animation');
});
secondEl.addEventListener('animationend', () => {
  // start the 3rd animation
  thirdEl.classList.add('animation');
});
// etc

例子

这是一个带有链式动画的示例(来自 docs):

const animation = document.querySelector('p.animation');
const animationEventLog = document.querySelector('.animation-example>.event-log');
const applyAnimation = document.querySelector('.animation-example>button.activate');
let iterationCount = 0;

animation.addEventListener('animationstart', () => {
  animationEventLog.textContent = `${animationEventLog.textContent}'animation started' `;
});

animation.addEventListener('animationiteration', () => {
  iterationCount++;
  animationEventLog.textContent = `${animationEventLog.textContent}'animation iterations: ${iterationCount}' `;
});

animation.addEventListener('animationend', () => {
  animationEventLog.textContent = `${animationEventLog.textContent}'animation ended'`;
  animation.classList.remove('active');
  applyAnimation.textContent = "Activate animation";
});

animation.addEventListener('animationcancel', () => {
  animationEventLog.textContent = `${animationEventLog.textContent}'animation canceled'`;
});

applyAnimation.addEventListener('click', () => {
  animation.classList.toggle('active');
  animationEventLog.textContent = '';
  iterationCount = 0;
  let active = animation.classList.contains('active');
  if (active) {
    applyAnimation.textContent = "Cancel animation";
  } else {
    applyAnimation.textContent = "Activate animation";
  }
});
.container {
  height: 3rem;
}

.event-log {
  width: 25rem;
  height: 2rem;
  border: 1px solid black;
  margin: .2rem;
  padding: .2rem;
}

.animation.active {
  animation-duration: 2s;
  animation-name: slidein;
  animation-iteration-count: 2;
}

@keyframes slidein {
  from {
    margin-left: 100%;
    width: 300%;
  }
  to {
    margin-left: 0%;
    width: 100%;
  }
}
<div class="animation-example">
  <div class="container">
    <p class="animation">You chose a cold night to visit our planet.</p>
  </div>
  <button class="activate" type="button">Activate animation</button>
  <div class="event-log"></div>
</div>