1

当我动态添加一个使用 JS 动画的项目时,如何让它们在同一时间轴上同步,如下所示:http: //youtube.com/watch ?v=AGiTmjFHs8M&t=9m23s ?我看到一个教程显示了使用 JS 动画与 CSS 的好处是它们继承了相同的时间线。

<div class="body"></div>
<button onclick="addItem()">Add</button>

function addItem() {
   let body = document.querySelector('.body');
   let newEl = document.createElement('div');
   newEl.innerText = "I am a new Item";
   newEl.animate([
      { 
          transform: 'translate(0px, 0px)',
          transform: 'translate(500px, 500px)',
      }
      ], 
      {
         duration: 2000,
         iterations: Infinity,
      });

   body.appendChild(newEl);
}
4

1 回答 1

1

如果您的所有动画对象都共享相同的duration内容并且您希望它们同时开始和结束,您可以简单地将新动画对象的iterationStartEffectTiming设置为已经运行的动画对象的ComputedTiming值。 但是请注意,在获取前一个动画对象的计算值之前,您必须等待新的动画对象准备好,否则您将迟到一帧。为此,您可以简单地等待Promise。 .progress
animation.ready

要获取之前的 Animation 对象,您可以在创建它时通过 存储它,也Element.animate()可以通过 访问文档上当前运行的动画集document.getAnimations(),然后从那里选择它。

let i = 0;
async function addItem() {

  i++;
  const body = document.querySelector(".body");
  const newEl = document.createElement("div");
  newEl.classList.add("item");
  newEl.textContent = "I am a new Item " + i;

  // get a previous Animation if any
  const previous_animation = document.getAnimations()[0];

  // create the new Animation object
  // slightly offset on the x axis only
  // to check if they are indeed in sync
  const anim = newEl.animate([{
    transform: "translate(" + (i * 10) + "px, 0px)",
    transform: "translate(" + (i * 10 + 250) + "px, 250px)",
  }], {
    duration: 2000,
    iterations: Infinity
  });
  // when it's ready to start
  await anim.ready;

  // get the current progress of the first Animation object
  const computed_timing = previous_animation?.effect.getComputedTiming();
  if( computed_timing ) {
    // update our new Animation object to the same progress value
    anim.effect.updateTiming( {
      iterationStart: computed_timing.progress
    });
  }
  
  body.appendChild(newEl);

}
.item {
  position: absolute;
}
<div class="body"></div>
<button onclick="addItem()">Add</button>


请注意,正如用户brianskold在下面的评论中指出的那样,动画的startTime属性可以设置为更早的时间。这样做会让它就像动画在这个时候开始一样。

因此,对于同步两个动画,这可能是最好的方法:

let i = 0;
function addItem() {

  i++;
  const body = document.querySelector(".body");
  const newEl = document.createElement("div");
  newEl.classList.add("item");
  newEl.textContent = "I am a new Item " + i;

  // get a previous Animation if any
  const previous_animation = document.getAnimations()[0];

  // create the new Animation object
  // slightly offset on the x axis only
  // to check if they are indeed in sync
  const anim = newEl.animate([{
    transform: "translate(" + (i * 10) + "px, 0px)",
    transform: "translate(" + (i * 10 + 250) + "px, 250px)",
  }], {
    duration: 2000,
    iterations: Infinity
  });

  if( previous_animation ) {
    // set the startTime to the same
    // as the previously running's one
    // note this also forces anim.ready to resolve directly
    anim.startTime = previous_animation.startTime;
  }

  body.appendChild(newEl);

}
.item {
  position: absolute;
}
<div class="body"></div>
<button onclick="addItem()">Add</button>

于 2020-12-30T06:27:51.117 回答