【问题标题】:How to know programmatically which is the last object that has the animation如何以编程方式知道哪个是最后一个具有动画的对象
【发布时间】:2022-02-05 09:19:23
【问题描述】:

有没有办法让我以编程方式知道 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 应用动画的元素。

【问题讨论】:

  • 我不太确定你在追求什么:在最后一个动画完成时收到通知,并确定它是哪一个,或者识别,独立于实际运行的动画,哪个将最后完成,或者获得.r3上的动画什么时候结束(因为你提前知道它会是最后一个)?
  • 您能否更详细地描述“检测”的含义。这只是 JS 中查找动画延迟和动画持续时间设置的一些代码,可以完成,还是以某种方式测量页面加载和 r3 上动画结束之间的时间,这不能完成(嗯,不完全准确,因为我们不在实时系统环境中)。

标签: javascript css svg css-animations


【解决方案1】:

Web Animations API 可以检查动画。

document.getAnimations() 返回文档中找到的所有动画。它们每个都有一个effect 属性,在您的情况下,它们都是KeyframeEffect 类型。

  • animation.animationName 返回 CSS @keyframes 声明中所述的动画名称。
  • animation.effect.target 返回动画所针对的元素。
  • animation.effect.getComputedTiming().endTime 返回动画结束的时间。

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

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>

【讨论】:

  • 哇!非常感谢。我在找这个。
  • @ccprog:非常感谢您提供这个出色的示例!关于错误的 console.log 输出:它实际上出现了......但相当延迟。这种奇怪的行为似乎与animation.effect.target 调用的“完整”节点输出有关,而它仍在动画中。将此行更改为 animation.effect.target.id 将绕过此问题。
  • @herrstrietzel:哦,是的。那是我本可以想到的自己……(嗯,不是)。谢谢你的提示。
  • @ccprog:我的荣幸!实际上,我认为遗憾的是,与下一个终极框架(引入过多的依赖模块)相比,这些相当新的(......仍处于即战斗模式)本机支持的 ​​API 功能/改进在一般意义上略微倾向于“不为人知” .
【解决方案2】:

您可以尝试使用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 推送到一个数组并将其与现有的 no 进行比较,该 no 表示 DOM 中的动画元素的编号(可以使用唯一的类来获取这些动态的)。当animatedElementsnoOfElementsToAnimate 相等时,我删除侦听器并记录/使用animatedElements 数组的最后一个值。

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

【讨论】:

    【解决方案3】:

    我想出了这个方法,它计算每个 svg 元素的 Delay+(Duration*Iteration-Count),最后返回该表达式的最大值,这将是动画运行的最后一个元素的总持续时间。逻辑上,动画的最后一个元素将具有最长的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>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多