video.play() 和 video.pause() 是唯一直接、跨浏览器有效的控制方式;需检查 paused 状态、处理 play() 的 Promise 拒绝、监听 play/pause 事件同步 UI、移动端用 touchstart(含 passive: false)、CSS 双保险隐藏原生控件。

video.play() 和 video.pause() 是唯一可靠入口
浏览器原生控件靠 controls 属性开关,但自定义按钮必须走 JS API。别试图用 CSS 隐藏后模拟点击——video.play() 和 video.pause() 是唯一直接、跨浏览器有效的控制方式。
常见错误是直接调用 play() 却没处理 Promise 拒绝(比如用户未交互就自动播放被拦截),或在 paused 为 true 时仍调用 pause()(会报错但不中断,但逻辑混乱)。
- 始终先检查状态:
if (video.paused)再决定调用play()还是pause() - 对
play()的返回 Promise 做基础兜底:video.play().catch(e => console.warn('Autoplay prevented:', e)) - 不要依赖
video.ended判断是否可播——它只在播完后为true,初始状态和暂停中都是false
按钮文本/图标切换必须监听 play/pause 事件
仅靠点击事件更新按钮文字是脆弱的:用户可能用空格键、快捷键、其他按钮甚至脚本触发播放,点击 handler 无法感知。
正确做法是把状态同步逻辑从点击事件里抽出来,统一由媒体事件驱动:
立即学习“前端免费学习笔记(深入)”;
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- 监听
video.addEventListener('play', () => { btn.textContent = '⏸'; }) - 监听
video.addEventListener('pause', () => { btn.textContent = '▶'; })</li> <li>初始状态也要设:<code>btn.textContent = video.paused ? '▶' : '⏸';
如果用图标字体或 SVG,建议用 class 切换而非改 textContent,避免中文编码或渲染延迟问题。
移动端 touchstart 替代 click 是硬性要求
iOS Safari 和部分安卓浏览器对 click 有 300ms 延迟,且某些场景下 click 根本不触发(比如视频容器内层无 focusable 元素)。touchstart 才是移动端可靠起点。
- 绑定事件时写:
btn.addEventListener('touchstart', handler, { passive: false }) -
{ passive: false }必须加,否则 iOS 下preventDefault()失效,影响后续play() - 为兼容桌面端,可同时绑定:
btn.addEventListener('click', handler); btn.addEventListener('touchstart', handler);
注意:不要用 ontouchstart 行内属性,它无法被 JS 动态移除或复用。
隐藏原生控件不能只靠 controls="false"
controls="false" 只是移除属性,某些浏览器(如旧版 Edge)仍可能显示默认控件;更稳妥的是双保险:
- HTML 层面去掉
controls属性:<video id="myVideo"></video>,不要写controls="false" - CSS 层面强制隐藏伪元素:
video::-webkit-media-controls { display: none !important; } - 额外加一行:
video { -webkit-appearance: none; },防 Safari 意外渲染
只做一半容易在某个机型上突然弹出原生按钮,覆盖你的自定义 UI——这种问题往往上线后才暴露,调试成本高。


















