如何在作品集网站中实现带菜单的视频播放器?
可以用 HTML 的 <video> 元素配合一组菜单按钮实现。每个按钮保存一个视频地址,用户点击后,JavaScript 将地址赋给播放器的 src,再调用 play()。普通的作品集视频列表用浏览器原生功能就能完成,无须引入播放器库。
这种方案适用于可以直接访问的视频文件。如果视频托管在 YouTube 等平台,需要使用平台提供的嵌入播放器及其 API,不能把视频观看页面的地址直接填入 <video src>。
实现步骤
- 用
<video controls>显示播放器,保留浏览器自带的播放、音量和进度控制。 - 用
<button>创建视频列表,通过data-src保存各视频的路径。 - 为按钮绑定
click事件,点击时切换视频、更新选中状态并请求播放。 - 在加载失败或浏览器阻止播放时,向用户显示提示。
菜单用普通按钮即可,按钮本身支持键盘操作。如果使用 role="menu",还需要额外实现相应的键盘交互逻辑。
完整代码示例
将下面的代码保存为 index.html,在同级目录创建 videos 文件夹,放入对应视频。文件名可以自行修改,但要与代码中的路径一致。
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>作品视频</title>
<style>
.video-gallery {
max-width: 900px;
margin: 2rem auto;
padding: 0 1rem;
}
video {
display: block;
width: 100%;
background: #000;
}
.video-list {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
padding: 0;
list-style: none;
}
.video-list button {
padding: 0.6rem 1rem;
cursor: pointer;
}
.video-list button[aria-current="true"] {
color: #fff;
background: #2457c5;
}
.video-list button:focus-visible {
outline: 3px solid #2457c5;
outline-offset: 3px;
}
</style>
</head>
<body>
<section class="video-gallery" aria-labelledby="gallery-title">
<h1 id="gallery-title">作品视频</h1>
<video
id="player"
src="videos/project-a.mp4"
controls
playsinline
preload="metadata"
aria-label="作品视频播放器"
>
你的浏览器不支持 HTML 视频播放。
</video>
<ul class="video-list" aria-label="选择作品">
<li>
<button
type="button"
data-src="videos/project-a.mp4"
aria-current="true"
>
项目 A
</button>
</li>
<li>
<button type="button" data-src="videos/project-b.mp4">
项目 B
</button>
</li>
</ul>
<p id="status" role="status"></p>
</section>
<script>
const player = document.querySelector("#player");
const buttons = document.querySelectorAll(".video-list button");
const status = document.querySelector("#status");
let selectionId = 0;
buttons.forEach((button) => {
button.addEventListener("click", async () => {
const currentSelection = ++selectionId;
buttons.forEach((item) => {
item.removeAttribute("aria-current");
});
button.setAttribute("aria-current", "true");
status.textContent = "";
player.pause();
player.src = button.dataset.src;
player.load();
try {
await player.play();
} catch (error) {
// 快速切换视频时,忽略上一次播放请求的结果。
if (currentSelection !== selectionId) return;
if (error.name === "AbortError") return;
status.textContent =
error.name === "NotAllowedError"
? "浏览器未允许播放,请点击播放器上的播放按钮。"
: "无法播放该视频,请检查文件地址和视频格式。";
}
});
});
player.addEventListener("error", () => {
status.textContent =
"视频加载失败,请检查文件路径、网络或视频格式。";
});
</script>
</body>
</html>
页面打开后会显示第一个视频,但不会自动播放。点击任意菜单项,播放器会从所选视频的开头开始播放;再次点击同一项,也会重新开始。
data-src 是自定义数据属性,可以通过 button.dataset.src 读取。设置 player.src 后,load() 会重置媒体状态并重新加载资源。play() 返回 Promise,需要处理播放请求失败的情况。
selectionId 用来区分连续点击产生的播放请求,避免旧请求失败后覆盖当前视频的提示。
使用时需要注意什么
视频地址必须指向媒体文件
videos/project-a.mp4 是相对于当前 HTML 页面的路径。部署后如果视频无法加载,先打开浏览器开发者工具的 Network 面板,检查请求是否返回 404,以及返回的内容是否确实是视频文件。
仅凭文件扩展名无法判断视频能否播放。浏览器是否支持该视频,取决于容器格式及其中的视频、音频编码,需要在目标浏览器和手机上实际检查。
保留原生播放控件
点击菜单后调用 play(),仍可能受到浏览器播放策略的限制,因此代码保留了 controls。即使浏览器拒绝脚本的播放请求,用户仍可点击播放器上的播放按钮。
playsinline 用于请求在支持的移动浏览器中行内播放,具体表现取决于浏览器和设备。
按需要添加字幕和封面
有讲解或对白的视频,可以通过 <track kind="captions"> 加载 WebVTT 字幕。需要封面时,设置 <video> 的 poster 属性即可。如果每段视频使用不同的封面,切换视频时也应更新 player.poster。
preload="metadata" 是给浏览器的预加载提示,实际加载多少数据由浏览器决定。视频较大时,还应控制文件大小,并检查实际网络环境下的加载速度。
自学时搜索哪些资料
可以在 MDN Web Docs 中查找这些条目:
<video>:了解controls、poster、preload和<source>。HTMLMediaElement.play():查看 Promise、播放限制及异常处理。HTMLMediaElement.load():查看切换资源时的加载行为。HTMLElement.dataset:学习如何读取data-*属性。EventTarget.addEventListener():学习事件绑定。<track>和 WebVTT:查看字幕的添加方式。
也可以直接搜索:
HTML video playlist JavaScript
JavaScript change video src
HTMLMediaElement play Promise NotAllowedError
HTML video 自定义播放列表
HTML video 切换视频源
如果需要点击菜单跳到同一个视频的不同章节,可以搜索 HTMLMediaElement.currentTime 或“HTML video 章节跳转”,通过设置播放时间实现。
备注:内容仅供参考。
