<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)这种方式获取封面的时候,当我在上传过程中切换浏览器标签页代码就会到这里就不执行了下面代码了就卡到这里了,怎么样不受浏览器在不在当前页面都可以正常执行获取封面
有没有方法可以实现这种批量上传的时候获取封面图不受浏览器在不在当前页面的限制;