Skip to content

媒体属性与 API

HTML5 的 HTMLMediaElement API 提供了丰富的 JavaScript 接口来控制 <audio><video> 的播放行为。本节将介绍常用的媒体属性、方法和事件,帮助你构建自定义播放器。

前置知识

阅读本节前,建议先了解:track 字幕与文本轨道

基础概念

<audio><video> 元素共享同一个 JavaScript 接口 —— HTMLMediaElement。通过这个 API,你可以用 JavaScript 控制播放/暂停、调整音量、跳转播放位置、监听播放事件等,从而构建自定义的媒体播放器界面。

掌握这些 API 是构建高级媒体应用(如视频编辑器、自定义播放器、音频可视化等)的基础。

语法

基本控制方法

javascript
// 获取媒体元素
var video = document.getElementById('myVideo');

// 播放
video.play();

// 暂停
video.pause();

// 跳转到第 30 秒
video.currentTime = 30;

// 设置音量为 50%
video.volume = 0.5;

// 静音
video.muted = true;

// 切换播放速度(1.5 倍速)
video.playbackRate = 1.5;
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>媒体 API</title>
</head>
<body>
  <h1>媒体 API 基础</h1>

  <video id="myVideo" src="movie.mp4" width="400" height="225"></video>
  <br>

  <button onclick="playVideo()">播放</button>
  <button onclick="pauseVideo()">暂停</button>
  <button onclick="muteVideo()">静音/取消静音</button>

  <script>
    var video = document.getElementById('myVideo');

    function playVideo() {
      video.play();
    }

    function pauseVideo() {
      video.pause();
    }

    function muteVideo() {
      video.muted = !video.muted;
    }
  </script>
</body>
</html>

详细说明

HTMLMediaElement 常用属性

属性类型说明示例
currentTime数值当前播放时间(秒)video.currentTime = 30;
duration数值总时长(秒,只读)var len = video.duration;
paused布尔是否暂停(只读)if (video.paused) {...}
ended布尔是否播放结束(只读)if (video.ended) {...}
volume数值音量(0.0~1.0)video.volume = 0.5;
muted布尔是否静音video.muted = true;
playbackRate数值播放速率video.playbackRate = 1.5;
buffered对象已缓冲的时间范围video.buffered.end(0)
readyState数值就绪状态if (video.readyState >= 2)

常用方法

方法说明
play()开始播放(返回 Promise)
pause()暂停播放
load()重新加载媒体源
canPlayType(type)检测是否支持指定格式

常用事件

事件触发时机
play开始播放
pause暂停播放
ended播放结束
timeupdate播放位置更新
volumechange音量或静音状态改变
loadedmetadata元数据(时长、尺寸)加载完成
canplay有足够数据可以开始播放
waiting因缓冲不足而暂停
error加载出错

canPlayType 检测格式支持

javascript
var video = document.createElement('video');

// 检测是否支持 WebM VP9
var canWebM = video.canPlayType('video/webm; codecs=vp9');
// 返回值:"probably"、"maybe" 或 ""

// 检测是否支持 MP4 H.264
var canMP4 = video.canPlayType('video/mp4; codecs=avc1.42E01E');

console.log('WebM VP9:', canWebM);    // "probably" 或 "maybe"
console.log('MP4 H.264:', canMP4);    // "probably" 或 "maybe"

实战示例

自定义视频播放器

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>自定义播放器</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      max-width: 700px;
      margin: 0 auto;
      padding: 20px;
    }
    .player {
      background: #111;
      border-radius: 12px;
      overflow: hidden;
    }
    .player video {
      width: 100%;
      display: block;
    }
    .controls {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 12px 16px;
      color: #fff;
    }
    .controls button {
      background: none;
      border: none;
      color: #fff;
      font-size: 20px;
      cursor: pointer;
      padding: 4px;
    }
    .progress-bar {
      flex: 1;
      height: 6px;
      background: #444;
      border-radius: 3px;
      cursor: pointer;
      position: relative;
    }
    .progress {
      height: 100%;
      background: #e74c3c;
      border-radius: 3px;
      width: 0%;
    }
    .time {
      font-size: 13px;
      color: #aaa;
      white-space: nowrap;
      min-width: 90px;
      text-align: center;
    }
    .speed-btn {
      font-size: 13px !important;
      padding: 4px 8px !important;
      background: #333 !important;
      border-radius: 4px;
    }
  </style>
</head>
<body>
  <div class="player">
    <video id="video" src="movie.mp4" preload="metadata"></video>

    <div class="controls">
      <button id="playBtn" title="播放/暂停">&#9654;</button>
      <div class="progress-bar" id="progressBar">
        <div class="progress" id="progress"></div>
      </div>
      <span class="time" id="timeDisplay">0:00 / 0:00</span>
      <button class="speed-btn" id="speedBtn">1x</button>
      <button id="muteBtn" title="静音">&#128264;</button>
    </div>
  </div>

  <script>
    var video = document.getElementById('video');
    var playBtn = document.getElementById('playBtn');
    var progressBar = document.getElementById('progressBar');
    var progress = document.getElementById('progress');
    var timeDisplay = document.getElementById('timeDisplay');
    var speedBtn = document.getElementById('speedBtn');
    var muteBtn = document.getElementById('muteBtn');

    // 格式化时间
    function formatTime(seconds) {
      var mins = Math.floor(seconds / 60);
      var secs = Math.floor(seconds % 60);
      return mins + ':' + (secs < 10 ? '0' : '') + secs;
    }

    // 播放/暂停
    playBtn.addEventListener('click', function() {
      if (video.paused) {
        video.play();
      } else {
        video.pause();
      }
    });

    // 更新播放/暂停图标
    video.addEventListener('play', function() {
      playBtn.innerHTML = '&#9646;&#9646;'; // 暂停图标
    });
    video.addEventListener('pause', function() {
      playBtn.innerHTML = '&#9654;'; // 播放图标
    });

    // 更新进度条和时间
    video.addEventListener('timeupdate', function() {
      var pct = (video.currentTime / video.duration) * 100;
      progress.style.width = pct + '%';
      timeDisplay.textContent =
        formatTime(video.currentTime) + ' / ' + formatTime(video.duration);
    });

    // 点击进度条跳转
    progressBar.addEventListener('click', function(e) {
      var rect = progressBar.getBoundingClientRect();
      var pct = (e.clientX - rect.left) / rect.width;
      video.currentTime = pct * video.duration;
    });

    // 播放速度切换
    var speeds = [1, 1.25, 1.5, 2];
    var speedIndex = 0;
    speedBtn.addEventListener('click', function() {
      speedIndex = (speedIndex + 1) % speeds.length;
      video.playbackRate = speeds[speedIndex];
      speedBtn.textContent = speeds[speedIndex] + 'x';
    });

    // 静音切换
    muteBtn.addEventListener('click', function() {
      video.muted = !video.muted;
      muteBtn.innerHTML = video.muted ? '&#128263;' : '&#128264;';
    });

    // 播放结束
    video.addEventListener('ended', function() {
      playBtn.innerHTML = '&#9654;';
      progress.style.width = '0%';
    });
  </script>
</body>
</html>

注意事项

  • play() 方法返回 Promise,需要处理可能的拒绝(如浏览器阻止自动播放)
  • currentTimeduration 的单位是秒(浮点数)
  • playbackRate 设置过高可能导致音频失真
  • 事件监听器应尽早绑定(在 DOM 加载后立即绑定)
  • 移动端浏览器的某些 API 行为可能不同

最佳实践

  • 使用 play().catch() 处理自动播放被阻止的情况
  • 使用 timeupdate 事件更新进度条(而非 setInterval
  • canPlayType 检测格式支持,提供合适的媒体源
  • 使用 loadedmetadata 事件获取视频时长后再初始化 UI
  • 自定义播放器时应保持键盘可访问性
  • 使用 requestAnimationFrame 处理与媒体同步的动画

下一节

继续学习:媒体格式兼容性

参考链接