如何以编程方式知道哪个是具有动画的最后一个对象

How to know programmatically which is the last object that has the animation

有没有办法让我以编程方式知道 CSS 动画最后应用在哪个对象上

例如,

.r1 {
     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;
}
 .c1 {
     animation-name: blink;
     animation-delay: 0.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 /*.text1 {
     animation-name: scl;
     animation-delay: 5.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}*/
 .r2 {
     transform-origin: center;
     transform-box: fill-box;
     animation-name: gr;
     animation-delay: 3.5s;
     animation-duration: 2s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 .r3 {
     animation-name: move2;
     animation-delay: 7.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);
    }
}
 @keyframes blink {
     from {
         opacity: 0;
    }
     to {
         opacity: 1;
    }
}
 @keyframes gr {
     from {
         transform: rotate(0deg);
    }
     to {
         transform: rotate(359deg);
    }
}
 @keyframes scl {
     to {
         transform: scale(1.1);
    }
}  
 @keyframes move2 {
     to {
         transform: translateY(400px);
    }
}  
        }
  <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
  <rect id="r1" class="r1" x="10" y="20" width="100" height="100" fill="red" />
  <rect id="r2" class="r2" x="10" y="130" width="100" height="100" fill="green" />
  <rect id="r3" class="r3" x="10" y="240" width="100" height="100" fill="blue" />

  <circle id="c1" class="c1" cx="50" cy="400" r="40" fill="orange" />
  <text class="text1" id="text1" x="80" y="500" font-size="30" fill="red">I love SVG!</text>
</svg>

在此,我有 5 个元素,我正在对其中的 4 个元素应用动画,r3 是应用动画的最后一个元素。有没有一种方法可以检测 r3animation-delay+animation-duration - 动画应用 javascript.

的最后一个元素

您可以像这样使用 animationend 来实现此目的 :-

const animatedElements = [];
const noOfElementsToAnimate = 4;
const svgLayer = document.querySelector('#Layer_1');

const onAnimationEnd = (e) => {
  animatedElements.push(e.target.id);
  if (animatedElements.length === noOfElementsToAnimate) {
    svgLayer.removeEventListener('animationend', onAnimationEnd);
    console.log(animatedElements[animatedElements.length - 1])
  }
}

svgLayer.addEventListener('animationend', onAnimationEnd);
.r1 {
  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;
}

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


/*.text1 {
     animation-name: scl;
     animation-delay: 5.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}*/

.r2 {
  transform-origin: center;
  transform-box: fill-box;
  animation-name: gr;
  animation-delay: 3.5s;
  animation-duration: 2s;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
  animation-direction: normal;
  animation-fill-mode: forwards;
}

.r3 {
  animation-name: move2;
  animation-delay: 7.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);
  }
}

@keyframes blink {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes gr {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}

@keyframes scl {
  to {
    transform: scale(1.1);
  }
}

@keyframes move2 {
  to {
    transform: translateY(400px);
  }
}


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

  <circle id="c1" class="c1" cx="50" cy="400" r="40" fill="orange" />
  <text class="text1" id="text1" x="80" y="500" font-size="30" fill="red">I love SVG!</text>
</svg>

说明: - 这里我将 animationend 事件的事件侦听器附加到父元素,即 Layer_1 svg. 每当动画为其子元素结束时,我将该元素的 id 推入一个数组并将其与现有编号进行比较,该编号表示 DOM 中的动画元素编号(可以使用一个独特的 class 也可以动态获取它们)。当 animatedElementsnoOfElementsToAnimate 相等时,我删除侦听器和 log/use animatedElements 数组的最后一个值。

或者,您也可以放弃数组,只使用一个变量来跟踪最后一个动画元素,例如,lastAnimatedElement 并递减 noOfElementsToAnimate 并记录 lastAnimatedElementnoOfElementsToAnimate 是 0.

我想到了这个,它计算每个 svg 元素的 Delay+(Duration*Iteration-Count),最后 returns 该表达式的最大值,这将是最后一个元素的总持续时间动画 运行。从逻辑上讲,带有动画的最后一个元素将具有最长的 Delay+(Duration*Iteration-Count),我需要将其作为 animation-delay 传递给我的下一个动画元素。

var _layer1 = document.querySelectorAll('svg > *');
var _max = -1;
for (const el of _layer1) {
    var __del = getComputedStyle(el).animationDelay;
    var __del = __del.split(',');
    var __delLast = parseFloat(__del[__del.length - 1]);
    var __duration = getComputedStyle(el).animationDuration;
    var __duration = __duration.split(',');
    var __durationLast = parseFloat(__duration[__del.length - 1]);
    var __iterationCount = getComputedStyle(el).animationIterationCount;
    var __iterationCount = __iterationCount.split(',');
    var __iterationCountLast = parseFloat(__iterationCount[__iterationCount.length - 1]);

    function alternate(a, b) {
        if (isNaN(a)) {
            return b
        } else {
            return a
        }
    };
    var modified = alternate(__iterationCountLast, __durationLast);
    var _expression = __delLast + (__durationLast * modified); //Delay+(Duration*Iteration-Count)
    _max = Math.max(_max, _expression);
};
.r1 {
     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;
}
 .c1 {
     animation-name: blink;
     animation-delay: 0.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 /*.text1 {
     animation-name: scl;
     animation-delay: 5.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}*/
 .r2 {
     transform-origin: center;
     transform-box: fill-box;
     animation-name: gr;
     animation-delay: 3.5s;
     animation-duration: 2s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 .r3 {
     animation-name: move2;
     animation-delay: 7.5s;
     animation-duration: 2s;
     animation-iteration-count: infinite;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 @keyframes move1 {
     to {
         transform: translateX(200px);
    }
}
 @keyframes blink {
     from {
         opacity: 0;
    }
     to {
         opacity: 1;
    }
}
 @keyframes gr {
     from {
         transform: rotate(0deg);
    }
     to {
         transform: rotate(359deg);
    }
}
 @keyframes scl {
     to {
         transform: scale(1.1);
    }
}  
 @keyframes move2 {
     to {
         transform: translateY(400px);
    }
}  
        }
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
</svg>

Web Animations API可以检查动画。

document.getAnimations() returns 在文档中找到的所有动画。他们每个人都有一个 effect 属性,在你的例子中,他们都是 KeyframeEffect.

类型
  • animation.animationName returns CSS @keyframes 声明中的动画名称。
  • animation.effect.target returns 动画所针对的元素。
  • animation.effect.getComputedTiming().endTimereturns动画结束的时间。

从那里您可以比较和过滤您需要的信息。

document.getAnimations().forEach(animation => {
    console.log(
        animation.animationName,
        animation.effect.target.id,
        animation.effect.getComputedTiming().endTime
    );
});
.r1 {
     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;
}
 .c1 {
     animation-name: blink;
     animation-delay: 0.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 /*.text1 {
     animation-name: scl;
     animation-delay: 5.5s;
     animation-duration: 1s;
     animation-iteration-count: 2;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}*/
 .r2 {
     transform-origin: center;
     transform-box: fill-box;
     animation-name: gr;
     animation-delay: 3.5s;
     animation-duration: 2s;
     animation-iteration-count: 1;
     animation-timing-function: ease-in;
     animation-direction: normal;
     animation-fill-mode: forwards;
}
 .r3 {
     animation-name: move2;
     animation-delay: 7.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);
    }
}
 @keyframes blink {
     from {
         opacity: 0;
    }
     to {
         opacity: 1;
    }
}
 @keyframes gr {
     from {
         transform: rotate(0deg);
    }
     to {
         transform: rotate(359deg);
    }
}
 @keyframes scl {
     to {
         transform: scale(1.1);
    }
}  
 @keyframes move2 {
     to {
         transform: translateY(400px);
    }
}
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
  <rect id="r1" class="r1" x="10" y="20" width="100" height="100" fill="red" />
  <rect id="r2" class="r2" x="10" y="130" width="100" height="100" fill="green" />
  <rect id="r3" class="r3" x="10" y="240" width="100" height="100" fill="blue" />

  <circle id="c1" class="c1" cx="50" cy="400" r="40" fill="orange" />
  <text class="text1" id="text1" x="80" y="500" font-size="30" fill="red">I love SVG!</text>
</svg>