You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么Safari 15无法触发audio.onended等音频事件?该如何修复?

Safari 15 audio.onended事件不触发修复方案

该问题的核心触发原因是Safari 15对HTMLMediaElement的事件绑定、资源处理逻辑与Chromium内核浏览器存在差异,直接对onended属性赋值事件处理器的写法在该版本下存在兼容缺陷。可按以下优先级尝试修复:

  • 方案一:改用addEventListener绑定事件,同时添加事件清理逻辑避免内存泄漏,替换原有useEffect代码如下:
useEffect(() => {
  if (audio === null) return
  const handleAudioEnded = () => console.log('hello')
  audio.addEventListener('ended', handleAudioEnded)
  // 组件卸载/依赖更新时清理监听
  return () => {
    audio.removeEventListener('ended', handleAudioEnded)
  }
}, [audio])

该方案解决了直接赋值onended被Safari内置逻辑覆盖、事件无法注册的问题,是优先推荐的修复方式。

  • 方案二:显式配置audio元素属性,添加playsInline声明、禁用loop属性。Safari 15在未显式配置playsInline时会默认调用系统级音频播放器接管播放流程,结束事件不会传回页面层的audio实例。
    若为React创建的audio元素,直接在标签上加playsInline={true};原生JS创建的实例可通过audio.playsInline = true手动赋值。
  • 方案三:添加兜底的播放进度监听逻辑,针对Safari特殊场景做兼容。如果上述两种方案都无法生效,可通过timeupdate事件实时判断播放进度,接近音频总时长时手动触发结束逻辑:
useEffect(() => {
  if (audio === null) return
  const handlePlayProgress = () => {
    // 剩余播放时长小于0.1s时判定为播放结束,可根据业务场景调整阈值
    if (!audio.paused && audio.duration - audio.currentTime < 0.1) {
      console.log('hello')
      audio.pause()
    }
  }
  audio.addEventListener('timeupdate', handlePlayProgress)
  return () => {
    audio.removeEventListener('timeupdate', handlePlayProgress)
  }
}, [audio])

额外注意:Safari对音频资源的请求校验更为严格,需要确保音频资源的CORS配置正确,且服务端支持Range范围请求、响应头返回正确的Content-Range字段,资源加载异常也会导致结束事件无法正常触发。

内容的提问来源于stack exchange,提问作者Jeremiah Caballero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 14:27:04