代码之家  ›  专栏  ›  技术社区  ›  Fernandossmm

element.animate()使用关键帧似乎忽略了放松功能

  •  0
  • Fernandossmm  · 技术社区  · 1 年前

    我正在尝试制作一个前后弹跳的CSS动画,每一端都有一个停顿。使用Javascript方法element.animate()似乎可以做到这一点,只是使用关键帧会破坏轻松功能,而仅使用CSS时不会发生这种情况。

    我用animate()错了吗?是虫子吗?为什么Javascript和CSS的行为不同?这个 animate MDN docs 对此不要说任何话。

    const element = document.getElementById("animation")
    const anim = element.animate(
      [
        { offset: 0, transform: "translateX(0)" },
        { offset: .1, transform: "translateX(0)" },
        { offset: .9, transform: "translateX(50vw)" },
        { offset: 1, transform: "translateX(50vw)" },
      ],
      {
        duration: 5000,
        easing: "ease-in-out",
        direction: "alternate",
        iterations: Infinity,
      }
    );
    <div id="animation">Ball</div>

    在CSS中创建相同的动画需要正确的放松。

    const element = document.getElementById("animationJS")
    const anim = element.animate(
      [
        { offset: 0, transform: "translateX(0)" },
        { offset: .1, transform: "translateX(0)" },
        { offset: .9, transform: "translateX(50vw)" },
        { offset: 1, transform: "translateX(50vw)" },
      ],
      {
        duration: 5000,
        easing: "ease-in-out",
        direction: "alternate",
        iterations: Infinity,
      }
    );
    #animationCSS {
        animation-name: move;
        animation-direction: alternate;
        animation-duration: 5s;
        animation-timing-function: ease-in-out;
        animation-iteration-count: infinite;
    }
    
    @keyframes move {
        from {
          transform: translateX(0);
        }
        10% {
            transform: translateX(0);
        }
        90% {
            transform: translateX(50vw);
        }
        to {
            transform: translateX(50vw);
        }
    }
    <div id="animationJS">Ball1</div>
    <div id="animationCSS">Ball2</div>

    但是,我不能使用CSS,因为我希望以编程方式更改关键帧百分比/偏移量。

    此外,删除JS代码中中间的两个关键帧可以修复它,但它仍然不是我想要的。

    1 回复  |  直到 1 年前
        1
  •  0
  •   somethinghere    1 年前

    如果删除动画中任何令人困惑的方面(因为缓和在整个值范围内进行,所以它从0开始,到1结束,这意味着你错过了缓和部分的前10%和最后10%),并使值稍微大一点,以真正看到缓和的效果,你会注意到它目前如预期的那样工作。很容易被动画弄糊涂,尤其是那些微妙的动画。

    const element = document.getElementById("animation")
    const anim = element.animate(
      [
        { offset: 0, transform: "translateX(0)" },
        { offset: 1, transform: "translateX(100vw) translateX(-100%)" },
      ],
      {
        duration: 5000,
        easing: "ease-in-out",
        direction: "alternate",
        iterations: Infinity,
      }
    );
    #animation { position: absolute; left: 0; top: 0; }
    <div id="animation">Ball</div>

    你可以在上面的片段中看到这一点:加速,减速: ease-in-out 正在按预期工作。不过,我可以看到你试图实现的目标,使用一个时间线在动画时间线之间有20%的间隔,但据我所知,这种放松适用于你的 整体 时间表。因此,您可能需要设置一个无限循环来添加延迟:

    async function delay( ms ){
        
      return new Promise(r => setTimeout(r, ms));
      
    }
    async function loopAnimation(){
      
      const element = document.getElementById("animation")
    
      let direction = 'normal';
      let animation;
    
      while( true ){
        
        await delay(1000);
        
        // Make sure previous an animations are removed and don't stack up
        if( animation ) animation.cancel();
        
        animation = element.animate([
          { offset: 0, transform: "translateX(0)" },
          { offset: 1, transform: "translateX(100vw) translateX(-100%)" },
        ],{
          duration: 3000,
          easing: "ease-in-out",
          direction: direction,
          iterations: 1,
          fill: 'both'
        })
      
        await animation.finished;
        await delay(1000);
        
        // Reverse the animation
        direction = direction === 'normal' ? 'reverse' : 'normal';
    
      }
    
    }
    
    loopAnimation();
    #动画{位置:绝对;左侧:0;顶部:0;}
    <div id=“animation”>球</div>

    让我们合并您的示例

    正如你在下面看到的,动画99%是相同的,我想差异只是JS和加载的时间上的微小差异,但它们运行的几乎完全相同(我确实必须在JS中更正你的动画,所以它 .9 而不是 .8 作为偏移):

    const element = document.getElementById("animate-js")
    const anim = element.animate(
      [
        { offset: 0, transform: "translateX(0)" },
        { offset: .1, transform: "translateX(0)" },
        { offset: .9, transform: "translateX(10vw)" },
        { offset: 1, transform: "translateX(10vw)" },
      ],
      {
        duration: 5000,
        easing: "ease-in-out",
        direction: "alternate",
        iterations: Infinity,
      }
    );
    #animate-css {
      animation-name: move;
      animation-direction: alternate;
      animation-duration: 5s;
      animation-timing-function: ease-in-out;
      animation-iteration-count: infinite;
      color: red;
    }
    
    @keyframes move {
      from {
        transform: translateX(0);
      }
      10% {
        transform: translateX(0);
      }
      90% {
        transform: translateX(10vw);
      }
      to {
        transform: translateX(10vw);
      }
    }
    <div id="animate-js">Animate</div>
    <div id="animate-css">Animate</div>

    事实上,不,奇怪的是 因为您试图在循环中添加延迟:

    const element = document.getElementById("animate-js")
    const anim = element.animate(
      [
        { offset: 0, transform: "translateX(0)" },
        { offset: 1, transform: "translateX(10vw)" },
      ],
      {
        duration: 5000,
        easing: "ease-in-out",
        direction: "alternate",
        iterations: Infinity,
      }
    );
    #animate-css {
      animation-name: move;
      animation-direction: alternate;
      animation-duration: 5s;
      animation-timing-function: ease-in-out;
      animation-iteration-count: infinite;
      color: red;
    }
    
    @keyframes move {
      from {
        transform: translateX(0);
      }
      to {
        transform: translateX(10vw);
      }
    }
    <div id=“animate js”>动画</div>
    <div id=“animate css”>动画</div>

    如果没有这一点,它们是完全同步的。

        2
  •  0
  •   Fernandossmm    1 年前

    我已经找到了解决方案,相应的JS代码与CSS代码的工作原理相同。

    const element = document.getElementById("animationJS")
    const anim = element.animate(
      [
        { offset: 0, transform: "translateX(0)" },
        { offset: .1, transform: "translateX(0)", easing: "ease-in-out" },
        { offset: .9, transform: "translateX(50vw)"},
        { offset: 1, transform: "translateX(50vw)" },
      ],
      {
        duration: 5000,
        direction: "alternate",
        iterations: Infinity,
      }
    );
    #animationCSS {
        animation-name: move;
        animation-direction: alternate;
        animation-duration: 5s;
        animation-timing-function: ease-in-out;
        animation-iteration-count: infinite;
    }
    
    @keyframes move {
        from {
          transform: translateX(0);
        }
        10% {
            transform: translateX(0);
        }
        90% {
            transform: translateX(50vw);
        }
        to {
            transform: translateX(50vw);
        }
    }
    <div id="animationJS">Ball1</div>
    <div id="animationCSS">Ball2</div>

    只在动画的中间部分添加缓和功能,并将其从整体中删除,就可以达到目的。

    我不知道为什么它是这样工作的,我在文档中找不到这个具体的区别,但至少它是有效的。