_花海 2025-06-29 14:53 采纳率: 0%
浏览 11
已结题

vue3批量上传,切换浏览器标签页不执行代码问题


<input class="posi-a left0 bottom0 top0 right0 opacity0" accept="image/png, image/jpeg, image/gif, video/mp4, video/mpeg, video/3gpp, video/x-msvideo, video/quicktime" multiple
          type="file" name="" @change="inputUploadChange">
          

var uploadArr = [], oldArr = [];
function uploadStart(files) {
  
    if (files.length == 0) {
        ElMessage.warning("未检测到文件");
        return false;
    }
    pageData.updateIng = true;
    var beforeNum = fileDatas.list.length;//记录这次上传之前 已经上传了多少个
    files.forEach(n => {
        n.numIndex = beforeNum;
    let data = {
            numIndex: beforeNum,//记录索引
            url: '',
            nameStatus:n.name,
            name: n.name.split('.')[0],
            typeName:n.name.split('.')[1],
      type:n.type.split('/')[0],
            newSize: (n.size / 1024 / 1024).toFixed(2) + 'MB',
            size: n.size,
            check: false,
            width: '0%',
            estimated: '0MB/s',
            state: 0,
            videoDuration: 0
        }
        fileDatas.list.push(data)
        
        beforeNum++;
    })
    uploadArr = files.splice(0, 1);
    oldArr = files;
    startUpload(uploadArr);
}
var timer = '', overNum = 0;//上传完几个
function overUpload() {
    overNum++;
    clearTimeout(timer);
    timer = setTimeout(() => {
        uploadArr.splice(0, overNum); //去掉上传队列中上传完的
        if (oldArr.length) {
            var arr = oldArr.splice(0, overNum); //拿几个补到到上传队列
            overNum = 0;//初始上传完成数
            uploadArr = [...arr, ...uploadArr];
            startUpload(arr);//开始上传
        }
    }, 500)
}
function startUpload(arr) {
    for (var i = 0; i < arr.length; i++) {
        uploadFun(arr[i]);
    }
}

/**
 * 获取视频封面并以 Base64 格式返回
 * @param {string} videoUrl - 视频地址
 * @returns {Promise<string>} 返回封面图片的 Base64 数据 URL
 */
 function getVideoCoverAsBase64(videoUrl) {
  return new Promise((resolve, reject) => {
    const video = document.createElement('video');
    video.crossOrigin = 'anonymous'; // 如果是跨域视频,需要设置这个属性
    video.src = videoUrl;
    video.preload = 'auto';

    video.onloadeddata = () => {
      // 设置当前播放时间为视频的第一帧
      video.currentTime = 0;
    };

    video.onseeked = () => {
      // 创建 canvas 来绘制视频帧
      const canvas = document.createElement('canvas');
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;

      const ctx = canvas.getContext('2d');
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

      // 将图像导出为 Base64 格式的 Data URL
      const base64Image = canvas.toDataURL('image/jpeg'); // 可改为 image/png

      resolve(base64Image);
    };

    video.onerror = (err) => {
      reject(new Error('加载视频失败: ' + err.message));
    };
  });
}
async function uploadFun(item,key) {
  try {
    let data = pageData.newData.find(val=>val.name==item.name) //记录上传视频item
    if(!data){
        pageData.newData.push(item)
    }
    const CancelToken = axios.CancelToken;
    const source = CancelToken.source();
    cancelTokens[item.name] = source; 
    let nowIndex = item.numIndex;//i+beforeNum; //取到当前正在上传的索引
  const fileSuffix = item.type.split("/")[1]; // 获取文件后缀

    if(item.type.split("/")[0]=='video'){ //只有视频的时候才需要
  }else{
    fileDatas.list[nowIndex].thumbnailUri = ''
    fileDatas.list[nowIndex].videoDuration = 0; // 图片的时长
    fileDatas.list[nowIndex].bitRate = 0; // 图片的码率
  }
  // 获取视频或者图片的md5值
  const md5 = await getFileMD5(item)
  fileDatas.list[nowIndex].fileMd5 = md5
    fileDatas.list[nowIndex].state = 3;
    let now=new Date();
  // 检查是否已有该后缀的配置
  if (!uploadConfigCache[fileSuffix]) {
      // 没有配置,先获取配置
      await new Promise(resolve => {
          commonUploadVideo({
              fileData: item,
              Random: now.getTime(),
              fileSuffix: fileSuffix,
              dramaId: fileDatas.list[nowIndex].materialUserId
          }, (formData, ossUrl, fileData, filePrefix) => {
              // 存储配置
              uploadConfigCache[fileSuffix] = {
                  formData: formData,
                  ossUrl: ossUrl,
                  fileData: fileData,
                  filePrefix:filePrefix,
              };
              resolve();
          });
      });
  }
  // 从缓存中获取配置
  const { formData, ossUrl, fileData,filePrefix } = uploadConfigCache[fileSuffix];
    // 生成唯一文件名
    const uniqueFileName = `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const fullFilePrefix = `${filePrefix}/${uniqueFileName}`;
    // 复制表单数据并更新key
    const updatedFormData = { ...formData };
    
    updatedFormData.key = `${fullFilePrefix}.${fileSuffix}`;

        let param = new FormData();
    // console.log(formData);
    
        for (var k in updatedFormData) {
            param.append(k, updatedFormData[k]);
        }
        param.append("file", item);
        let uploadTime = (new Date()).getTime();
        let oldByte = 0;
        const res = await axios.request({
            url: ossUrl,
            method: 'post',
            headers: { "Content-Type": "multipart/form-data" },
            data: param,
      timeout:3600000, //超时时间1小时
            onUploadProgress: function (progressEvent) {
                var { progress, estimated, loaded } = progressEvent;
                fileDatas.list[nowIndex].width = progress * 100 + '%';
                let nowTime = (new Date()).getTime();
                if (nowTime - uploadTime > 1000) {
                    let nowByte = (loaded - oldByte) / 1024 / 1024;
                    fileDatas.list[nowIndex].estimated = nowByte.toFixed(2) + 'MB/s';
                    uploadTime = nowTime;
                    oldByte = loaded;
                }
            },
            cancelToken: source.token
        });
        console.log(res);
            if (res.code == 0) {
                fileDatas.list[nowIndex].state = 1;
                fileDatas.list[nowIndex].url = res.results.wholeUrl;
        getMediaInfo(res.results.wholeUrl).then(res=>{
          fileDatas.list[nowIndex].newWidth = res.width; // 视频/图片的宽
          fileDatas.list[nowIndex].newHeight = res.height;
          if(item.type.split("/")[0]=='video'){ //只有视频的时候才需要
            fileDatas.list[nowIndex].videoDuration = res.duration; // 视频的时长
            fileDatas.list[nowIndex].bitRate = res.bitrate; // 视频的码率
          }
        })
        if(porpData.query.materialUserId){
          options.src = res.results.wholeUrl
        }
            } else {
                fileDatas.list[nowIndex].state = 2;
            }
            
            fileDatas.list.forEach((item, idx) => {  
                item.numIndex = idx;  
            }); 
            pageData.newData.forEach((item, idx) => {  
                item.numIndex = idx;  
            }); 
    // console.log(dataUrl);
    
    
    
  if(item.type.split("/")[0]=='video'){ //只有视频的时候才需要
    // 检查是否已有该后缀的配置
    if (!uploadConfigCache.jpg) {
        // 没有配置,先获取配置
        await new Promise(resolve => {
            commonUploadVideo({
                fileData: item,
                Random: now.getTime(),
                fileSuffix: 'jpg',
                dramaId: fileDatas.list[nowIndex].materialUserId
            }, (formData, ossUrl, fileData, filePrefix) => {
                // 存储配置
                uploadConfigCache.jpg = {
                    formData: formData,
                    ossUrl: ossUrl,
                    fileData: fileData,
                    filePrefix:filePrefix,
                };
                resolve();
            });
        });
    }
    const { formData, ossUrl, fileData,filePrefix } = uploadConfigCache.jpg;
    getVideoCoverAsBase64(fileDatas.list[nowIndex].url).then(async(dataUrl)=>{
        // 获取第一针视频封面的oss地址
        const ImageformData = dataURLtoFile(dataUrl);

        // 生成唯一文件名
        const uniqueFileName = `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        const fullFilePrefix = `${filePrefix}/${uniqueFileName}`;
        // 复制表单数据并更新key
        const updatedFormData = { ...formData };

        updatedFormData.key = `${fullFilePrefix}.jpg`;

        let newD = new FormData();


        for (var k in updatedFormData) {
          newD.append(k, updatedFormData[k]);
        }
        newD.append("file", ImageformData);
        await axios.request({
          url: ossUrl,
          method: 'post',
          headers: { "Content-Type": "multipart/form-data" },
          data: newD,
          cancelToken: source.token
        }).then(res=>{
          fileDatas.list[nowIndex].thumbnailUri = res.results.wholeUrl;
        })
    })
    
  }
  var success = fileDatas.list.filter(n => n.state > 0);
  if (success.length == fileDatas.list.length) { //上传完了
    pageData.updateIng = false;
  } else {
    if(!key){
      overUpload();
    }
  }
  }catch (error) {
    if (!key) {
      overUpload();
    } else {
      fileDatas.list[nowIndex].state = 2;
    }
  }
}

在vue3中这个方法(uploadFun)是我循环上传文件(视频或者图片每次上传一个)的方法,但是现在遇到一个问题就是getVideoCoverAsBase64方法获取视频的首针封面的时候如果我在批量上传过程中切换浏览器标签页或者我最小化浏览器的时候就会出现这个方法getVideoCoverAsBase64不执行了等到回到当前浏览器标签页的时候才会批量执行,怎么修改getVideoCoverAsBase64方法或者用什么方式才能不受浏览器在不在当前标签页都可以继续执行获取封面图,也就是只要调用这个方法就可以获取封面,跟上面的代码同时执行;
之前我使用await getVideoCoverAsBase64(fileDatas.list[nowIndex].url)这种方式获取封面的时候,当我在上传过程中切换浏览器标签页代码就会到这里就不执行了下面代码了就卡到这里了,怎么样不受浏览器在不在当前页面都可以正常执行获取封面
有没有方法可以实现这种批量上传的时候获取封面图不受浏览器在不在当前页面的限制;

  • 写回答

4条回答 默认 最新

  • 阿里嘎多学长 2025-06-29 14:55
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    问题解答

    你遇到的问题是:在使用 Vue 3 批量上传文件时,切换浏览器标签页后,上传代码不执行。

    解决方案

    这个问题是因为 Vue 3 的生命周期钩子函数在切换标签页时不会被重新执行。可以使用 beforeunload 事件来解决这个问题。

    在你的 Vue 组件中添加以下代码:

    mounted() {
      window.addEventListener('beforeunload', () => {
        // 你的上传代码
      });
    }
    

    这样,在用户切换标签页时,beforeunload 事件将被触发,执行你的上传代码。

    如果你想在切换标签页时也执行其他代码,可以使用 beforeunload 事件的回调函数来实现。

    注意

    在使用 beforeunload 事件时,需要注意浏览器的兼容性问题。一些浏览器可能不支持这个事件。

    如果你遇到其他问题或需要更多帮助,请随时问我。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 6月29日
  • 创建了问题 6月29日