如何同步在不同时间启动/重新启动的 CSS 动画

133*_*der 6 javascript css

我正在尝试同步接收相同动画类的多个页面元素的 CSS 动画。

\n

似乎有很多关于这个主题的帖子,但没有统一的解决方案,而且我找到的解决方案似乎都不适用于这种情况。

\n

我在这里准备了一个jsfiddle来演示这个问题:

\n

https://jsfiddle.net/gdf7szo5/1/

\n

如果您单击任何字母,它将启动该字母的动画。如果您再次单击,它将切换到不同的动画,如果您第三次单击,它将把字母设置为根本没有动画。

\n

期望的效果是一个动画中闪烁的所有字母彼此同步,并且另一动画中的任何字母彼此同步。需要明确的是,我并不是试图同步两个动画 \xe2\x80\x94 我只是希望具有给定动画的所有元素彼此同步。

\n

但目前,如果一个字母显示动画,而您将另一个字母设置为同一动画,除非您有绝对完美的时机,否则这两个字母的动画将不同步,即使它们是相同的动画。

\n

这是正在运行的代码:

\n

HTML:

\n
<div>\n  <span id="spA" onclick="toggleFx(\'spA\')">A</span>\n  <span id="spB" onclick="toggleFx(\'spB\')">B</span>\n  <span id="spC" onclick="toggleFx(\'spC\')">C</span>\n  <span id="spD" onclick="toggleFx(\'spD\')">D</span>\n</div>\n
Run Code Online (Sandbox Code Playgroud)\n

CSS:

\n
div {\n  display: flex;\n  flex-flow: column;\n}\n\nspan {\n  animation-name: pulse_active;\n}\n\nspan.pulse {\n    color: #f00;\n    animation: pulse_active 1.5s ease-in infinite;\n}\n\nspan.pulse_invert {\n  color: #00f;\n  animation: pulse_inverted 3s ease-in infinite;\n}\n\n@keyframes pulse_active {\n    0% {\n        opacity: 0;\n    }\n    50% {\n        opacity: 0.66;\n    }\n    100% {\n        opacity: 0;\n    }\n}\n\n@keyframes pulse_inverted {\n    0% {\n        opacity: 1;\n    }\n    50% {\n        opacity: 0.33;\n    }\n    100% {\n        opacity: 1;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

JS:

\n
let pulseNormal = {};\nlet pulseInvert = {};\n\nfunction toggleFx(spanID) {\n\n    let spanTarget = document.getElementById(spanID);\n  \n  // shift setting\n  if (spanID in pulseInvert) {\n  console.log(\'y\');\n  console.log(Object.keys(pulseInvert));\n    delete pulseInvert[spanID]\n  console.log(Object.keys(pulseInvert));\n  } else if (spanID in pulseNormal) {\n    pulseInvert[spanID] = true;\n    delete pulseNormal[spanID];\n  } else {\n    pulseNormal[spanID] = true\n  }\n  \n  // update display\n  for (let sp of \'ABCD\') {\n    let span = document.getElementById(`sp${sp}`);\n    \n    // clear any prev animation\n        span.classList.remove(\'pulse\');     \n    span.classList.remove(\'pulse_invert\');\n    \n    // add/re-add animation as needed\n    if (`sp${sp}` in pulseNormal) {             \n        span.classList.add(\'pulse\');\n    } else if (`sp${sp}` in pulseInvert) {\n        span.classList.add(\'pulse_invert\');\n    }\n  }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

小智 3

为此目的,document.getAnimations()有一个有用的方法。它返回当前有效的所有动画对象的数组,其目标元素是文档的后代。更多信息:https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations

document.getAnimations()include属性的项目currentTime,可用于同步动画。更多信息:https://drafts.c​​sswg.org/web-animations/#dom-documentorshadowroot-getanimations

toggleFx函数被修改,现在它由三个部分组成。

在第一部分中,搜索document.getAnimations()并查找currentTime属性,其中animationName是 或pulse_active之一pulse_inverted;然后将它们存储在相关变量中(即pulseActiveStartpulseInvertedStart)。

在第二部分,正如你所说的那样改变了classNamespanTarget

在第三部分中,pulseActiveStart应用于相关动画的属性(pulseInvertedStartcurrentTime第一部分相反)。

function toggleFx(spanID) {

    let spanTarget = document.getElementById(spanID);
    
    let  pulseActiveStart;
    let  pulseInvertedStart;
    let anims = document.getAnimations()    
    for(let i = 0; i < anims.length; i++) { 
        if(anims[i].animationName == "pulse_active") pulseActiveStart = anims[i].currentTime;
        else if(anims[i].animationName == "pulse_inverted") pulseInvertedStart = anims[i].currentTime;      
    }
    
    
    
    if(spanTarget.classList.contains('pulse_invert')) {
        spanTarget.classList.remove('pulse_invert');    
        spanTarget.classList.remove('pulse');   
    } else if(spanTarget.classList.contains('pulse')) {
        spanTarget.classList.add('pulse_invert');   
        spanTarget.classList.remove('pulse');   
    } else {
        spanTarget.classList.add('pulse');  
    }
    
    anims = document.getAnimations()    
    for(let i = 0; i < anims.length; i++) { 
        if(anims[i].animationName == "pulse_active") {
            if(pulseActiveStart) anims[i].currentTime = pulseActiveStart;           
        } else if(anims[i].animationName == "pulse_inverted") {
            if(pulseInvertedStart) anims[i].currentTime = pulseInvertedStart;       
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
div {
  display: flex;
  flex-flow: column;
}

span.pulse {
    color: #f00;
    animation: pulse_active 1.5s ease-in infinite;
}

span.pulse_invert {
  color: #00f;
  animation: pulse_inverted 3s ease-in infinite;
}

@keyframes pulse_active {
    0% { opacity: 0; }
    50% { opacity: 0.66; }
    100% {  opacity: 0; }
}

@keyframes pulse_inverted {
    0% { opacity: 1; }
    50% { opacity: 0.33; }
    100% {  opacity: 1; }
}
Run Code Online (Sandbox Code Playgroud)
<div>
  <span id="spA" onclick="toggleFx('spA')">A</span>
  <span id="spB" onclick="toggleFx('spB')">B</span>
  <span id="spC" onclick="toggleFx('spC')">C</span>
  <span id="spD" onclick="toggleFx('spD')">D</span>
</div>
Run Code Online (Sandbox Code Playgroud)