結(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)文章
vue3錨點(diǎn)定位兩種實(shí)現(xiàn)方式示例
這篇文章主要給大家介紹了關(guān)于vue3錨點(diǎn)定位兩種實(shí)現(xiàn)的相關(guān)資料,說(shuō)到錨點(diǎn)定位,很多人第一時(shí)間會(huì)想到 a標(biāo)簽,但是a標(biāo)簽實(shí)現(xiàn)的錨點(diǎn)定位并不是那么的完美,需要的朋友可以參考下2023-07-07
Vue通過(guò)echarts實(shí)現(xiàn)數(shù)據(jù)圖表化顯示
Echarts,它是一個(gè)與框架無(wú)關(guān)的 JS 圖表庫(kù),但是它基于Js,這樣很多框架都能使用它,例如Vue,估計(jì)IONIC也能用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
vue后臺(tái)管理之動(dòng)態(tài)加載路由的方法
這篇文章主要介紹了vue后臺(tái)管理之動(dòng)態(tài)加載路由的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
最全vue的vue-amap使用高德地圖插件畫多邊形范圍的示例代碼
這篇文章主要介紹了最全vue的vue-amap使用高德地圖插件畫多邊形范圍,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
vue實(shí)現(xiàn)多個(gè)數(shù)組合并
這篇文章主要介紹了vue實(shí)現(xiàn)多個(gè)數(shù)組合并方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
解決Vue3?echarts?v-show無(wú)法重新渲染的問(wèn)題
這篇文章主要介紹了Vue3?echarts?v-show無(wú)法重新渲染的問(wèn)題,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09

