Javascript 实时记录视频播放进度,防止观看作弊

背景

有一个需求,就是给学生发布了视频作业,记录学生的实际观看进度,防止拖动观看作弊等,以下是使用原生属性实现这个功能的步骤和代码示例。

最终效果图

HTML 结构

首先,我们需要设置基本的 HTML 结构,包括一个视频元素video标签和一个<input type="range">滑块元素:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Video Progress with Range Input</title>
  <style>
    /* 自定义样式 */
    input[type="range"]::-webkit-slider-runnable-track {
      border: none;
      border-radius: 5px;
      width: 100%;
      height: 10px;
    }
    input[type="range"] {
      -webkit-appearance: none;
      background: #dbeafe;
      margin: 10px 0;
      width: 100%;
      border-radius: 6px;
    }
    input[type="range"]::-webkit-slider-thumb {
      -webkit-appearance: none;
      height: 20px;
      width: 20px;
      border-radius: 50%;
      background: #117035;
      cursor: pointer;
      margin-top: -5px;
    }
  </style>
</head>
<body>
  <video id="myVideo" width="100%" height="300" controls>
    <source src="https://api.dogecloud.com/player/get.mp4?vcode=5ac682e6f8231991&userId=17&ext=.mp4" type="video/mp4" />
    Your browser does not support HTML5 video.
  </video>

  <input type="range" min="0" max="1" value="0" step="any" id="rangeInput" onchange="inputChange(event)" />
  <p>观看进度:<span id="watch"></span></p>

  <script>
    // JavaScript 代码将在这里
  </script>
</body>
</html>

JavaScript 功能实现

在 JavaScript 部分,主要包含以下部分:

  • 初始化视频的元数据:当视频的元数据加载完成时,我们设置滑块的最大值为视频的总时长,并初始化一个记录视频播放状态的对象,使视频和滑块事件相互绑定。
  • 更新时间更新:在视频播放过程中,我们不断更新滑块的值,并更新进度条的颜色来反映视频的观看状态。
  • 拖动范围输入:当用户拖动范围输入时,我们暂停视频并更新进度条的颜色。拖动结束后,视频会从新的位置开始播放。
  • 计算观看进度:计算用户观看视频的进度,并显示在页面上。以下是 JavaScript 代码的详细实现:

以下是 JavaScript 代码的详细实现:

const BLUE = "#dbeafe";
const GREEN = "#117035";

let isDragging = false;
let section = {};
let myArray1 = [];

const video = document.getElementById("myVideo");
const rangeInput = document.getElementById("rangeInput");
const watch = document.getElementById("watch");

// 监听视频加载实践,初始化滑块范围和记录对象
video.addEventListener("loadedmetadata", function () {
  console.log("视频duration:" + video.duration);
  let num = Math.floor(video.duration);
  rangeInput.max = num;
  // 因为我这视频一般较短,所以采用每秒记录,可以适当调整,比如5秒记录一次
  for (let i = 1; i <= num; i++) {
    section[i] = false;
  }
});

video.addEventListener("timeupdate", onTimeupdate);

async function onTimeupdate() {
  let currentTime = video.currentTime;
  let duration = video.duration;
  let progress = currentTime;
  rangeInput.value = progress;

  if (!section[Math.round(currentTime)]) {
  }
  section[Math.round(currentTime)] = true;
  await updateRangeColor();
}

video.addEventListener("play", function () {
  console.log("视频正在播放,当前播放时间" + video.currentTime);
  console.log(section);
});

video.addEventListener("pause", function () {
  console.log(section);
});

// 监听滑块拖动
rangeInput.addEventListener("input", function () {
  isDragging = true;
  let progress = rangeInput.value;
  let duration = video.duration;
  let currentTime = progress;
  video.currentTime = currentTime;
  video.pause();
  video.removeEventListener('timeupdate', onTimeupdate);
  updateRangeColor();
});

// 监听滑块拖动结束
rangeInput.addEventListener("change", function () {
  console.log("changechange");
  isDragging = false;
  video.addEventListener("timeupdate", onTimeupdate);
  video.play();
});

function groupByFlag(obj) {
  const result = [];
  let startTime = 0;
  for (let i = 1; i < Object.keys(obj).length; i++) {
    if (obj[i] !== obj[i - 1]) {
      result.push({ startTime, endTime: i - 1, flag: obj[i - 1] });
      startTime = 0;
    }
  }

  result.push({
    startTime,
    endTime: Object.keys(obj).length - 1,
    flag: obj[Object.keys(obj).length - 1],
  });

  return result;
}

// 根据记录更细滑块的背景色,感觉有点问题,有css大佬可以指点下
function updateRangeColor() {
  myArray1 = Object.keys(section).map(function (key) {
    return section[key];
  });
  let myArray = groupByFlag(section).filter(v => v.flag !== undefined);

  const colorSpan = myArray.length > 0 ? `linear-gradient(90deg,
      ${myArray.map((k, i) => {
          if (k.flag) {
            if (i === 0 && k.startTime === 0) {
              return `${GREEN} 0%, ${GREEN} ${(k.endTime / (myArray1.length - 1)) * 100}%, ${BLUE} ${(k.endTime /  (myArray1.length - 1)) * 100}%`;
            }
            return `${BLUE} ${(k.startTime / (myArray1.length - 1)) * 100}%, ${GREEN} ${ (k.startTime /  (myArray1.length - 1)) * 100 }%, ${GREEN} ${(k.endTime /  (myArray1.length - 1)) * 100}%, ${BLUE} ${ (k.endTime / (myArray1.length - 1)) * 100 }%`;
          } else {
            if (i === 0 && k.startTime === 0) {
              return `${BLUE} 0%, ${BLUE} ${(k.endTime / (myArray1.length - 1)) * 100}%, ${GREEN} ${(k.endTime / (myArray1.length - 1)) * 100}%`;
            }
            return `${GREEN} ${(k.startTime / (myArray1.length - 1)) * 100}%, ${BLUE} ${ (k.startTime / (myArray1.length - 1)) * 100 }%, ${BLUE} ${(k.endTime / (myArray1.length - 1)) * 100}%, ${GREEN} ${ (k.endTime / (myArray1.length - 1)) * 100 }%`;
          }
      })}` : `linear-gradient(90deg, blue 100%)`;
  rangeInput.style.background = colorSpan;
  watch.innerText = watchProcess() * 100 + '%';
}

function watchProcess() {
  let race = 0;
  myArray1.forEach(item => {
    if (item) race += 1;
  })

  return (race / (myArray1.length - 1)).toFixed(2);
}

function inputChange(e) {
  console.log(e.target.value);
}

总结 

上面实现了一个简单的基于原生video的具有动态颜色的进度条,可以有效地记录在视频中的观看进度。可以在上面的基础上拓展:

比如原生标签用其他的播放器代替(DPlayer等),可能相应的监听时间需要做修改。

比如将记录通过后台接口将记录写入在数据库,下次播放时读取记录继续播放等。

video标签中的视频播放进度可以通过JavaScript控制和获取。可以使用video元素的currentTime属性来获取或设置当前的播放时间(以秒为单位)。通过监听video元素的timeupdate事件,可以实时获取视频播放进度并更新进度条的显示。具体实现方法如下: 1. 首先获取video元素的引用,可以通过document.getElementById()或document.querySelector()方法来获取。 2. 给video元素添加一个timeupdate事件监听器,当视频播放时间更新时触发。 3. 在事件监听器内部,可以通过video.currentTime属性获取当前的播放时间。 4. 根据视频的总时长(video.duration属性)计算出进度百分比(当前播放时间/总时长),用于更新进度条的显示。 5. 可以使用HTML和CSS来创建一个进度条,通过JavaScript更新其宽度或位置来反映视频播放进度。 综上所述,您可以使用上述方法来实现video标签视频播放进度控制和显示。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [video标签播放视频无法拖动进度条(使用nginx解决)](https://blog.csdn.net/qq_34465338/article/details/124623067)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Html5新增标签video视频,实现音视频播放、暂停、快进、慢进、倍速等操作](https://blog.csdn.net/qq_51066068/article/details/124413984)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [H5(html5 video)视频播放禁止拖动进度条,不能快进,不能后退;微信公众号视频播放;Java视频播放](https://download.csdn.net/download/weixin_43992507/14503320)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值