css 更改动画播放状态会扰乱动画与音频的同步

x33g5p2x  于 2023-04-13  发布在  其他
关注(0)|答案(1)|浏览(186)

我正在将div滚动效果动画与音频同步,当音频暂停时,我将element.style.animation属性设置为'none'时,同步工作正常。问题是当音频暂停时,我尝试暂停动画。当我暂停并播放多次时,动画不再与音频同步(动画太高级)。

//This is the audio element
const pupHymn = document.querySelector(".pup-hymn");
//This is the container div of the lyrics
const hymnLyrics = document.querySelector(".lyrics");

const init = () => {
    pupHymn.volume = 0.3;
    //Sync when playing manually 
    pupHymn.addEventListener('play', () => {
        audioTime = pupHymn.currentTime;
        playbackRate = pupHymn.playbackRate;
        hymnLyrics.style.animation = `scroll-effect ${160/playbackRate}s ${(12-audioTime)/playbackRate}s forwards running`;
    );

    pupHymn.addEventListener('pause', () => {
        hymnLyrics.style.animation = 'none'; 
    });

//This works fine.
pupHymn.addEventListener('pause', () => {
        hymnLyrics.style.animation = 'none'; });
}

但是当我暂停animationPlayState时,当我暂停并播放多次时,它将无法正确同步。

pupHymn.addEventListener('pause', () => {
        hymnLyrics.style.animationPlayState = 'paused'; });

我已经尝试过记录我的div的animation属性,当音频播放时,即使延迟仍然是一个正值,动画已经开始了。

hsgswve4

hsgswve41#

这里最可靠的方法可能是通过Web Animation API,它允许你以相对较高的精度管理动画的当前时间。你可以挂钩到<audio>元素上的一些事件,并将它的.currentTimeMap到Animation.currentTime(注意前者是以秒为单位,而后者是以毫秒为单位)。

const audio = document.querySelector("audio");
const target = document.querySelector(".content");
audio.addEventListener("loadedmetadata", (evt) => {
  const { duration } = audio;
  const keys = new KeyframeEffect(
    target,
    [{ transform: "translate(0px, -1300px)" },],
    { duration: duration * 1000, fill: "forwards" }
  );
  const anim = new Animation(keys);
  const sync = () => anim.currentTime = audio.currentTime * 1000;
  audio.addEventListener("seeked", sync);
  audio.addEventListener("play", () => {
    sync();
    anim.play();
  });
  audio.addEventListener("pause", () => {
    anim.pause();
    sync();
  });
}, { once: true });
for (let i = 0; i < 46; i++) {
  const el = document.createElement("p");
  el.textContent = i;
  target.append(el);
}
.container {
  width: 300px;
  height: 300px;
  border: 1px solid;
  overflow: hidden;
}
.content {
  height: 1600px;
  background-image: linear-gradient(to bottom, red, blue);
}
.content p {
  margin-top: 0;
}
<audio controls src="https://upload.wikimedia.org/wikipedia/en/transcoded/d/dc/Strawberry_Fields_Forever_%28Beatles_song_-_sample%29.ogg/Strawberry_Fields_Forever_%28Beatles_song_-_sample%29.ogg.mp3"></audio>

<div class=container>
  <div class="content"></div>
</div>

相关问题