結(jié)合el-upload組件實(shí)現(xiàn)大文件分片上傳功能
前情提要
Element UI的el-upload上傳組件相信各位小伙伴都已經(jīng)非常熟悉,最近接了一個(gè)新需求,要求在el-upload組件基礎(chǔ)上實(shí)現(xiàn)分片上傳功能,即小于等于5M文件正常上傳,大于5M文件切成5M每片上傳。那么這個(gè)功能怎么實(shí)現(xiàn)呢?一起看看吧
代碼實(shí)現(xiàn)
首先,我們需要設(shè)置el-upload組件的http-request,這樣可以覆蓋默認(rèn)的上傳行為,可以自定義上傳的實(shí)現(xiàn)。
<!-- data是上傳時(shí)附帶的額外參數(shù),uploadFile是覆蓋默認(rèn)上傳的方法 -->
<el-upload :data="data" :http-request="uploadFile">
<el-button icon="el-icon-upload2">本地文件</el-button>
</el-upload>接下來(lái),uploadFile方法中需要區(qū)分文件是否超過(guò)5M
async uploadFile({ data, file }) {
// data是上傳時(shí)附帶的額外參數(shù),file是文件
let url = "xxx" //上傳文件接口
let loadingInstance = Loading.service({
text: "正在上傳文件,請(qǐng)稍后...",
});
try {
// 如果文件小于5MB,直接上傳
if (file.size < 5 * 1024 * 1024) {
let formData = new FormData();
for (let key in data) {
formData.append(key, data[key]);
}
formData.append("file", file);
const res = await upload(url,formData);
loadingInstance.close();
return res;
} else {
// 如果文件大于等于5MB,分片上傳
data.file = file;
const res = await uploadByPieces(url,data);
loadingInstance.close();
return res;
}
} catch (e) {
loadingInstance.close();
return e;
}
}upload方法就是正常上傳方法,uploadByPieces是分片上傳方法,我們可以把它們一個(gè)單獨(dú)的js文件中,方便我們使用。
upload方法:
const upload = (url, data, headers = {}) => {
return new Promise((resolve, reject) => {
axios({
url,
method: "post",
data,
headers: {
...headers,
'Content-Type': 'multipart/form-data'
}
}).then(res => {
return resolve(res.data)
}).catch(err => {
return reject(err)
})
})
}在uploadByPieces方法中我們可以使用file.slice對(duì)文件進(jìn)行切片
// 上傳過(guò)程中用到的變量
const chunkSize = 5 * 1024 * 1024; // 5MB一片
const chunkCount = Math.ceil(file.size / chunkSize); // 總片數(shù)
// 獲取當(dāng)前chunk數(shù)據(jù)
const getChunkInfo = (file, index) => {
let start = index * chunkSize;
let end = Math.min(file.size, start + chunkSize);
let chunk = file.slice(start, end);
return { start, end, chunk };
};File對(duì)象沒(méi)有定義任何方法,但它從Blob對(duì)象中繼承了slice方法:MDN
完整代碼
upload.vue
<template>
<el-upload :data="data" :http-request="uploadFile">
<el-button icon="el-icon-upload2">文件上傳</el-button>
</el-upload>
</template>
<script>
// 引入上傳文件方法
import { upload, uploadByPieces } from "@/utils/upload.js";
// Loading
import { Loading } from "element-ui";
export default {
props: ["data"],
methods: {
async uploadFile({ data, file }) {
// data是上傳時(shí)附帶的額外參數(shù),file是文件
let url = "xxx" //上傳文件接口
let loadingInstance = Loading.service({
text: "正在上傳文件,請(qǐng)稍后...",
});
try {
// 如果文件小于5MB,直接上傳
if (file.size < 5 * 1024 * 1024) {
let formData = new FormData();
for (let key in data) {
formData.append(key, data[key]);
}
formData.append("file", file);
const res = await upload(url,formData);
loadingInstance.close();
return res;
} else {
// 如果文件大于等于5MB,分片上傳
data.file = file;
const res = await uploadByPieces(url,data);
loadingInstance.close();
return res;
}
} catch (e) {
loadingInstance.close();
return e;
}
}
}
}
</script>upload.js
import axios from "axios";
//正常上傳
const upload = (url, data, headers = {}) => {
return new Promise((resolve, reject) => {
axios({
url,
method: "post",
data,
headers: {
...headers,
'Content-Type': 'multipart/form-data'
}
}).then(res => {
return resolve(res.data)
}).catch(err => {
return reject(err)
})
})
}
//分片上傳
const uploadByPieces = async (url,{ fileName, file }) => {
// 上傳過(guò)程中用到的變量
const chunkSize = 5 * 1024 * 1024; // 5MB一片
const chunkCount = Math.ceil(file.size / chunkSize); // 總片數(shù)
// 獲取當(dāng)前chunk數(shù)據(jù)
const getChunkInfo = (file, index) => {
let start = index * chunkSize;
let end = Math.min(file.size, start + chunkSize);
let chunk = file.slice(start, end);
return { start, end, chunk };
};
// 分片上傳接口
const uploadChunk = (data) => {
return new Promise((resolve, reject) => {
axios({
url,
method: "post",
data,
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
return resolve(res.data)
}).catch(err => {
return reject(err)
})
})
}
// 針對(duì)單個(gè)文件進(jìn)行chunk上傳
const readChunk = (index) => {
const { chunk } = getChunkInfo(file, index);
let fetchForm = new FormData();
fetchForm.append("chunk", chunk);
fetchForm.append("index", index);
fetchForm.append("chunkCount", chunkCount);
return uploadChunk(fetchForm)
};
// 針對(duì)每個(gè)文件進(jìn)行chunk處理
const promiseList = []
try {
for (let index = 0; index < chunkCount; ++index) {
promiseList.push(readChunk(index))
}
const res = await Promise.all(promiseList)
return res
}catch (e) {
return e
}
}
export { upload, uploadByPieces }到此這篇關(guān)于結(jié)合el-upload組件實(shí)現(xiàn)大文件分片上傳的文章就介紹到這了,更多相關(guān)el-upload大文件分片上傳內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Echarts2豎直datazoom滑動(dòng)后顯示數(shù)據(jù)不全的問(wèn)題
Vue實(shí)現(xiàn)購(gòu)物車計(jì)算總價(jià)功能
vue監(jiān)聽(tīng)瀏覽器的后退和刷新事件,阻止默認(rèn)的事件方式
vue 輸入框輸入任意內(nèi)容返回?cái)?shù)字的實(shí)現(xiàn)
vue實(shí)現(xiàn)個(gè)人信息查看和密碼修改功能
vue-cli構(gòu)建的項(xiàng)目如何手動(dòng)添加eslint配置
解決nuxt 自定義全局方法,全局屬性,全局變量的問(wèn)題

