HTML5 音频元素:播放音频的按钮的视觉元素在单击时不会更新,而是等到音频开始播放(移动 iOS 问题)

问题描述 投票:0回答:1

背景

我有一个按钮,当检测到

audio
事件时,可以播放连接到附近
click
元素的音频。
button
元素有一个嵌套的
img
元素,我将其
src
更改为指向各种 .svg 文件,具体取决于音频是否

  1. 播放(暂停图标)
  2. 暂停(播放图标)
  3. 即将播放但尚未开始播放(旋转缓冲图标)

问题

切换到暂停或播放图标完全没有问题,但是切换到缓冲图标发生得太晚,实际上并没有什么用处(即,用户单击播放按钮,用户等待多长时间,并且缓冲图标)在音频开始播放之前图标会闪烁几毫秒)。

在桌面上,这一切都非常快捷,甚至不需要缓冲图标,但在移动设备(iOS)上,从用户单击播放按钮到音频实际开始播放时可能会有一到四秒的延迟(这就是为什么我想要一个用于等待时间的缓冲图标)。

代码

HTML 结构

有很多这些

li
元素。这里真正的焦点是
button.playOrPauseBtn
元素:

<li>
    <audio
        id="TR-21"
        class="dialogueAudio"
        src="/static/audio/en/es/end/tr-21.mp3"
        preload="auto"
    >
    </audio>
    <div>
        <button type="button" class="svgBtn playOrPauseBtn" >
            <img class="playIcon" src="/static/svg/play.svg" height="22px" width="22px" />
        </button>
    </div>
</li>

javascript

这里的焦点是底部的事件监听器,我希望在单击按钮时立即将播放/暂停按钮的 UI 更改为我的缓冲区图标,但在移动设备上(iOS;还没有测试过的 android),它实际上会等待,然后仅在音频开始播放之前闪烁缓冲区图标(等待 1 到 4 秒,具体取决于音频)。

如果一切都被分成许多迷你函数看起来很奇怪,那是因为这些是实际函数的极其简化的版本(我试图只关注手头的问题)。他们对 UI 进行了更多操作,例如更改各种元素的标题和替代文本。 如果您认为以原始的、未简化的形式查看 JS 代码和 HTML 标记会有所帮助,请告诉我。

/* ----------------------------------------------
------------------- FUNCTIONS -------------------
---------------------------------------------- */

const changeAudioControlBtn = function(btn, svg, disabled=false, spinny=false) {
  // get other elements
  let btnImg = btn.querySelector("img");
  // change UI of btn
  btn.disabled = disabled;
  // change UI of img
  btnImg.src = svg;
  if (spinny === false) {
    btnImg.classList.remove("spinny");
  } else {
    btnImg.classList.add("spinny");
  }
}

/* Function to pause all audios */
const pauseAll = async function() {
  let allYeAudios = document.querySelectorAll("audio");
  allYeAudios.forEach((item, i) => {
    item.pause();
  });
};

/* Function for playing or pausing audio associated with play/pause button */
const playOrPause = async function(soundByte) {
  if (soundByte.paused == true) {
    // pause other audios before playing
    await pauseAll();
    soundByte.play();
  } else {
    soundByte.pause();
  }
};

/* Function to change play/pause button icon to play or pause symbol */
const changePlayOrPauseGraphics = function() {
  let playPauseBtn = this.parentElement.querySelector(".playOrPauseBtn");
  if (this.paused === true) {
    // set properties for function to change UI of play/pause btn
    let btn = playPauseBtn;
    let svg = "/static/svg/play.svg";
    changeAudioControlBtn(btn, svg);
  } else {
    // set properties for function to change UI of play/pause btn
    let btn = playPauseBtn;
    let svg = "/static/svg/pause.svg";
    changeAudioControlBtn(btn, svg);
  }
};

/* ----------------------------------------------
---------------- EVENT LISTENERS ----------------
---------------------------------------------- */

const allDialogueAudios = document.querySelectorAll(".dialogueAudio");

// Change visuals if playing
allDialogueAudios.forEach((item, i) => {
  item.addEventListener("playing", changePlayOrPauseGraphics);
});

// change visuals when audio pauses too
allDialogueAudios.forEach((item, i) => {
  item.addEventListener("pause", changePlayOrPauseGraphics);
});

const allPlayButtons = document.querySelectorAll(".playOrPauseBtn");

// Play buttons
allPlayButtons.forEach((item, i) => {
  item.addEventListener("click", () => {
    // set properties for UI function (to change btn to spinny buffer icon)
    let btn = item;
    let svg = "/static/svg/loady_spinner.svg";
    let disabled = true;
    let spinny = true;
    changeAudioControlBtn(btn, title, svg, alt, disabled, spinny);
    let soundByte = item.parentElement.parentElement.querySelector(".dialogueAudio");
    playOrPause(soundByte);
  });
});

我尝试过的事情

我曾经有调用

changeAudioControlBtn()
函数的代码,以便将
playOrPauseBtn
的 UI 更改为
playOrPause()
函数内的缓冲区图标,并且播放/暂停按钮的事件侦听器处理程序要简单得多(它只是调用了
playOrPause()
函数,但我认为将缓冲区图标更改的代码移至事件侦听器处理程序会更直接。但这没有任何效果。

其他详情

该问题似乎与 Safari 无关,因为它不会发生在 Safari 桌面上,而同样的问题发生在我的 iOS 设备上的 Chrome、Safari 和 Firefox 浏览器上。

javascript html ios audio event-handling
1个回答
0
投票

尝试使用

canplaythrough
事件,该事件在用户代理可以播放媒体时触发,并估计如果现在开始播放,媒体可以以当前播放速率一直渲染到结束,而无需停止进一步缓冲。

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canplaythrough_event

尝试这个方法:

// Play buttons allPlayButtons.forEach((item, i) => {   item.addEventListener("click", () => {
    // set properties for UI function (to change btn to spinny buffer icon)
    let btn = item;
    let svg = "/static/svg/loady_spinner.svg";
    let disabled = true;
    let spinny = true;
    changeAudioControlBtn(btn, title, svg, alt, disabled, spinny);
    let soundByte = item.parentElement.parentElement.querySelector(".dialogueAudio");
    soundByte.addEventListener('canplaythrough', () => {
      playOrPause(soundByte);
    });   }); });

在此代码中,仅当触发

playOrPause
事件时才会调用
canplaythrough
函数,以确保音频已准备好播放。这应该有助于在单击按钮后立即显示缓冲图标,并使其保持可见,直到音频开始播放。 此外,最好在多个平台上测试您的代码,以确保其按预期运行。

© www.soinside.com 2019 - 2024. All rights reserved.