You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript实现多视频文件上传时获取视频时长问题求助

多视频上传获取时长功能:问题排查与修复

核心问题分析

原代码存在以下几个关键错误:

  • 闭包变量陷阱:循环使用var i,异步回调onloadedmetadata触发时,循环已执行完毕,i值为files.length,导致myVideos[i]指向undefined,无法设置时长。
  • 未定义变量引用:updateInfos函数中total += myVideos[i].duration的i未定义,应使用当前循环变量j。
  • 原生File对象限制:直接给只读的File对象添加duration属性可能失效,需用自定义对象包装文件信息。
  • 异常值未处理:时长加载完成前调用updateInfos会显示NaN,需做默认值兼容。

修正后的完整代码

HTML(无需修改)

<div id="input-upload-file" class="box-shadow">
  <span>- Try Upload -</span> 
  <input type="file" class="upload" id="fileUp" name="fileUpload" multiple onchange="setFileInfo(this.files)">
</div>
<div id="infos"></div>

JavaScript(修复版)

const formatSeconds = seconds => {
  if (isNaN(seconds)) return "00:00:00";
  return new Date(seconds * 1000).toISOString().substr(11, 8);
};

let myVideos = [];
window.URL = window.URL || window.webkitURL;

function setFileInfo(files) {
  for (let i = 0; i < files.length; i++) {
    // 用自定义对象包装文件信息,避免修改原生只读File对象
    const videoItem = {
      file: files[i],
      duration: 0
    };
    myVideos.push(videoItem);

    const video = document.createElement('video');
    video.preload = 'metadata';
    video.src = URL.createObjectURL(files[i]);
    
    // 箭头函数绑定当前videoItem,彻底避免闭包索引问题
    video.onloadedmetadata = () => {
      window.URL.revokeObjectURL(video.src);
      videoItem.duration = video.duration;
      updateInfos();
    };
  }
}

function updateInfos(deleteName) {
  const info = document.querySelector('#infos');
  info.innerHTML = "";
  let total = 0;

  // 处理删除逻辑:用filter简化数组操作
  if (deleteName) {
    myVideos = myVideos.filter(item => item.file.name !== deleteName);
  }

  // 遍历渲染所有视频信息
  myVideos.forEach(item => {
    info.innerHTML += `<div class='row' data-name='${item.file.name}'>
                        <div class='close' onclick="remove(this)">&times;</div>
                        ${item.file.name}, duration: ${formatSeconds(item.duration)}
                      </div>`;
    total += item.duration;
  });

  // 显示总时长
  if (myVideos.length) {
    info.innerHTML += `<div class='row'>Total: ${formatSeconds(total)}</div>`;
  }
}

function remove(e) {
  updateInfos(e.parentNode.dataset.name);
}

修复关键点说明

  1. 块级作用域变量:用let i替代var i,确保每个循环迭代的回调能捕获正确的索引值。
  2. 自定义对象包装:用videoItem封装File对象和时长属性,绕过原生File对象的只读限制。
  3. 简化删除逻辑:使用filter方法替代倒序循环删除,代码更简洁且避免索引异常。
  4. 异常值处理:在formatSeconds中增加NaN判断,避免未加载完成时显示错误内容。
  5. 箭头函数规避闭包问题:直接引用当前循环的videoItem,彻底解决异步回调的变量绑定错误。

内容的提问来源于stack exchange,提问作者omar yaser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 18:55:27