PAYATHON 2026

如何在作品集网站中实现带菜单的视频播放器?

技术老齐

可以用 HTML 的 <video> 元素配合一组菜单按钮实现。每个按钮保存一个视频地址,用户点击后,JavaScript 将地址赋给播放器的 src,再调用 play()。普通的作品集视频列表用浏览器原生功能就能完成,无须引入播放器库。

这种方案适用于可以直接访问的视频文件。如果视频托管在 YouTube 等平台,需要使用平台提供的嵌入播放器及其 API,不能把视频观看页面的地址直接填入 <video src>。

实现步骤

  1. 用 <video controls> 显示播放器,保留浏览器自带的播放、音量和进度控制。
  2. 用 <button> 创建视频列表,通过 data-src 保存各视频的路径。
  3. 为按钮绑定 click 事件,点击时切换视频、更新选中状态并请求播放。
  4. 在加载失败或浏览器阻止播放时,向用户显示提示。

菜单用普通按钮即可,按钮本身支持键盘操作。如果使用 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 章节跳转”,通过设置播放时间实现。

备注:内容仅供参考。