HTML DOM Video played 属性(长文解析)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

前言:视频播放的“记忆体”

在现代网页开发中,视频互动功能已成为增强用户体验的重要手段。无论是在线教育平台的进度标记,还是直播应用的回放功能,开发者都需要精准控制视频播放状态。而 HTML DOM Video played 属性 就如同视频的“记忆体”,记录着用户已观看的时间范围。本文将从基础概念到实战案例,系统解析这一属性的使用方法,帮助开发者实现更智能的视频交互逻辑。


一、HTML DOM Video played 属性的核心概念

1.1 属性定义与作用

played 是 HTML5 <video> 元素的只读属性,返回一个 TimeRanges 对象,表示视频中已经被播放的时间范围。它的作用类似于“进度记忆器”,记录用户在视频中实际观看过的连续时间段。

形象比喻
可以想象 played 属性如同一本时间账簿,每当用户播放视频时,它就会记录下每个已播放的起止时间区间,即使用户拖动进度条或暂停播放,这些记录都会被完整保存。

1.2 TimeRanges 对象解析

TimeRanges 是浏览器内置的接口,包含以下核心方法和属性:

方法/属性描述
start(index)返回指定区间(从0开始计数)的起始时间(单位:秒)
end(index)返回指定区间的结束时间(单位:秒)
length返回记录的总区间数量

关键特性

  • 视频播放会动态更新 TimeRanges 内容,例如:
    • 播放后暂停:记录当前播放的起始到当前时间
    • 拖动进度条:新增对应区间的记录
    • 播放后快进:原有未播放的区间会被移除

二、如何获取和解析 played 属性

2.1 基础语法与代码示例

通过 JavaScript 直接访问 <video> 元素的 played 属性:

<video id="myVideo" controls>
  <source src="example.mp4" type="video/mp4">
</video>
const video = document.getElementById("myVideo");
const playedRanges = video.played;

console.log("已播放区间数量:", playedRanges.length);
console.log("第一个区间的起始时间:", playedRanges.start(0));
console.log("第一个区间的结束时间:", playedRanges.end(0));

执行结果示例
如果用户已播放到 15 秒并暂停,控制台可能输出:

已播放区间数量: 1
第一个区间的起始时间: 0
第一个区间的结束时间: 15

2.2 动态监听播放进度

通过结合 timeupdate 事件,可以实时跟踪播放状态:

video.addEventListener("timeupdate", () => {
  const currentPlayTime = video.currentTime;
  const isCurrentTimePlayed = isTimeInRanges(currentPlayTime);
  
  console.log(`当前时间 ${currentPlayTime} 秒是否已播放:`, isCurrentTimePlayed);
});

// 辅助函数:判断时间是否在已播放区间内
function isTimeInRanges(time) {
  for (let i = 0; i < video.played.length; i++) {
    const start = video.played.start(i);
    const end = video.played.end(i);
    if (time >= start && time < end) return true;
  }
  return false;
}

三、实际应用场景与代码实现

3.1 自定义进度条高亮显示

通过 played 属性可以实现“已观看”和“未观看”进度的可视化区分:

<div class="progress-bar">
  <div class="played-portion"></div>
  <div class="buffered-portion"></div>
</div>
function updateProgress() {
  const duration = video.duration;
  const played = video.played;
  
  // 计算已播放总时长
  let totalPlayed = 0;
  for (let i = 0; i < played.length; i++) {
    totalPlayed += played.end(i) - played.start(i);
  }
  
  // 更新样式(假设总进度条宽度为 300px)
  const progressWidth = (totalPlayed / duration) * 300;
  document.querySelector(".played-portion").style.width = `${progressWidth}px`;
}

video.addEventListener("timeupdate", updateProgress);

效果说明

  • 绿色区块(.played-portion)会随用户播放累积增长
  • 即使用户多次暂停/快进,也能准确统计有效观看时间

3.2 触发特定时间点的交互

结合 played 属性可实现“已播放到某章节”时显示提示:

function checkChapterCompletion() {
  const chapterTime = 60; // 第一章结束时间:1分钟
  if (isTimeInRanges(chapterTime)) {
    alert("恭喜!您已完成第一章的学习");
  }
}

// 在播放结束或特定时间点触发检查
video.addEventListener("ended", checkChapterCompletion);
video.addEventListener("timeupdate", () => {
  if (video.currentTime >= chapterTime) checkChapterCompletion();
});

四、关键注意事项与进阶技巧

4.1 浏览器兼容性问题

尽管现代浏览器均支持 played 属性,但需注意以下细节:

  1. 未加载时的空值问题
    在视频未开始加载时(如 video.readyState < 1),played.length 可能返回 0

    if (video.readyState >= HTMLMediaElement.HAVE_METADATA) {
      // 安全访问 played 属性
    }
    
  2. 动态内容的影响
    当视频源动态变化(如 src 属性修改)时,played 记录会被重置

4.2 性能优化建议

  • 避免高频访问 TimeRanges
    timeupdate 事件可能每秒触发多次,建议通过节流函数减少计算开销

    let lastUpdate = 0;
    function throttledUpdate() {
      if (Date.now() - lastUpdate > 200) {
        updateProgress();
        lastUpdate = Date.now();
      }
    }
    video.addEventListener("timeupdate", throttledUpdate);
    
  • 区分已播放与缓冲范围
    使用 buffered 属性配合 played 可实现更精细的进度控制

    const buffered = video.buffered;
    const bufferedEnd = buffered.end(buffered.length - 1);
    

五、完整案例:视频学习进度追踪系统

5.1 功能设计目标

  1. 实时显示已观看百分比
  2. 记录用户每次播放的连续区间
  3. 保存进度到本地存储(可选)

5.2 完整代码实现

<video id="videoPlayer" controls>
  <source src="lecture.mp4" type="video/mp4">
</video>
<div id="progressInfo">已观看: 0%</div>
const video = document.getElementById("videoPlayer");
const progressInfo = document.getElementById("progressInfo");

// 初始化本地存储(如需持久化)
let savedRanges = JSON.parse(localStorage.getItem("playedRanges")) || [];

function updateProgress() {
  if (video.readyState < 1) return; // 等待视频元数据加载

  const currentRanges = Array.from({ length: video.played.length }, (_, i) => ({
    start: video.played.start(i),
    end: video.played.end(i)
  }));

  // 合并新旧区间(防止重复记录)
  savedRanges = mergeRanges([...savedRanges, ...currentRanges]);
  
  // 更新显示
  const totalPlayed = savedRanges.reduce((sum, r) => sum + (r.end - r.start), 0);
  const percentage = (totalPlayed / video.duration) * 100;
  progressInfo.textContent = `已观看: ${percentage.toFixed(1)}%`;

  // 保存到本地存储(可选)
  localStorage.setItem("playedRanges", JSON.stringify(savedRanges));
}

// 辅助函数:合并重叠区间
function mergeRanges(ranges) {
  ranges.sort((a, b) => a.start - b.start);
  const merged = [];
  for (const range of ranges) {
    if (merged.length === 0) {
      merged.push(range);
    } else {
      const last = merged[merged.length - 1];
      if (range.start <= last.end) {
        last.end = Math.max(last.end, range.end);
      } else {
        merged.push(range);
      }
    }
  }
  return merged;
}

video.addEventListener("timeupdate", updateProgress);

结论:掌握视频播放的“时间之眼”

通过深入理解 HTML DOM Video played 属性,开发者能够构建更智能的视频交互系统。从基础的进度显示到复杂的学习进度追踪,这一属性为开发者提供了精准的“时间之眼”,帮助用户获得更个性化的体验。在实际开发中,需注意浏览器兼容性和性能优化,结合 bufferedcurrentTime 等属性,可以进一步拓展视频应用的功能边界。掌握这些技术后,您将能够更自信地应对视频类项目的开发挑战。

最新发布