说明
前端批量上传,嗯……一个一个上传
点击按钮【取消上传】可取消上传
通过将promise
的reject
保存到外部,调用函数终止操作
核心代码
const data = new Array(100).fill(0).map((_, i) => ({ uid: i }));
type ItemType = (typeof data)[number];
let settledNum = 0;
let successList: ItemType[] = [];
let failList: ({ reason: string } & ItemType)[] = [];
// 单个文件上传
const singleUpload = (item: ItemType) => {
console.log(item.uid);
return new Promise((resolve, reject) => {
if (item.uid % 3 == 0) {
return reject();
}
setTimeout(() => resolve(''), 50);
});
};
let abort: () => void;
// 批量上传处理函数
const __ = (): Promise<number | undefined> => {
return new Promise((resolve, reject) => {
const i = settledNum;
abort = reject; // reject 保存到外部 用于取消批量上传
singleUpload(data[i])
.then(
() => {
successList.push(data[i]);
},
(err) => {
failList.push({ ...data[i], reason: '上传失败' });
}
)
.finally(() => resolve(settledNum));
}).then(async () => {
settledNum++;
if (settledNum < data.length) {
return __();
}
});
};
// 批量上传
const batchUpload = async () => {
console.log('批量上传开始');
settledNum = 0;
successList = [];
failList = [];
await __();
console.log('批量上传结束', successList, failList);
};
// 取消上传
const handleCancel = () => {
console.log('取消上传');
if (abort) {
abort();
}
console.log('取消上传结束');
};
使用
batchUpload();
setTimeout(() => handleCancel(), 1000);
控制台输出
批量上传开始
0
1
// ...
29
取消上传
取消上传结束
栗子
文件:App.vue
<UploadLoading
:data="tableData"
:confirm-callback="confirmCallback"
:cancel-callback="cancelCallback"
/>
import { ref } from 'vue';
import UploadLoading from './components/UploadLoading.vue';
import type { ConfirmData, TableData } from './components/UploadLoading.vue';
const num = 200;
const tableData = ref<TableData>(
new Array(num).fill('').map((_, index) => ({ uid: String(index) }))
);
const confirmCallback = (val: ConfirmData) => {
console.log('--- confirmCallback ---', val);
};
const cancelCallback = () => {
console.log('--- cancelCallback ---');
};
组件:UploadLoading.vue
<div>
<div>
视频上传中
<span>{{ settledNum }}</span>
/
<span>{{ total }}</span>
</div>
<el-progress
:percentage="percentage"
text-inside
:stroke-width="20"
status="success"
></el-progress>
<div class="tip">
温馨提示:上传过程中请勿关闭页面,否则未上传的视频将取消上传
</div>
<el-button @click="handleCancel">取消上传</el-button>
</div>
import { computed, onMounted, ref } from 'vue';
import { delay, isArray } from 'lodash-es';
import { ElMessage, ElMessageBox } from 'element-plus';
export type TableData = {
uid: string;
}[];
export type ConfirmData = { successList: TableData; failList: TableData };
interface PropsType {
data: TableData;
confirmCallback: (val: ConfirmData) => void;
cancelCallback: () => void;
}
const props = withDefaults(defineProps<PropsType>(), {});
const settledNum = ref<number>(0);
const total = computed(() => props.data.length || 0);
const percentage = computed(() => {
return Math.floor((settledNum.value / total.value) * 100);
});
const singleUpload = (item: TableData[number]) => {
console.log('--- singleUpload ---', item.uid);
return new Promise((resolve, reject) => {
if (settledNum.value == 1) {
return reject({ reason: '上传失败' });
}
delay(() => resolve(''), 50);
});
};
let successList: TableData = [],
failList: TableData = [];
const batchUpload = async () => {
settledNum.value = 0;
successList = [];
failList = [];
await __();
props.confirmCallback({
successList,
failList,
});
ElMessage.success('上传成功');
};
let abort: () => void;
const __ = (): Promise<number | undefined> => {
return new Promise((resolve, reject) => {
const i = settledNum.value;
abort = reject; // reject 保存到外部 用于取消批量上传
singleUpload(props.data[i])
.then(
() => {
successList.push(props.data[i]);
},
(err) => {
failList.push(
Object.assign({}, props.data[i], { reason: err.reason })
);
}
)
.finally(() => resolve(settledNum));
}).then(async () => {
settledNum.value++;
if (settledNum.value < props.data.length) {
return __();
}
});
};
const handleCancel = async () => {
await ElMessageBox.alert('未上传的视频将停止上传,是否取消?', '提示', {
confirmButtonText: '取消上传',
});
if (abort) {
abort();
}
props.cancelCallback();
ElMessage.info('已取消上传');
};
onMounted(() => {
if (!(isArray(props.data) && props.data.length)) {
return props.cancelCallback();
}
batchUpload();
});