将文件进行切片,上传至服务器,上传完成后通知服务器进行合并文章来源:https://www.toymoban.com/news/detail-427417.html
屏幕录制2022-11-11 16.40.06文章来源地址https://www.toymoban.com/news/detail-427417.html
- 测试用例
<template>
<div name="test-upload-img">
<s-upload-img v-model="logo"></s-upload-img>
</div>
</template>
<script>
export default {
name: "test-upload-img",
extends: {},
mixins: [],
components: {},
emits: [],
props: {},
data() {
return {
logo: "zfs/2022-11-11/0ae8e4f733fe4bbdbb00f92fb1247273.jpeg"
}
},
created() {
},
methods: {}
}
</script>
- s-upload
<script>
import {getMinioUrl} from "../../../static/global.util";
export default {
name: "s-upload",
extends: {mixins: []},
components: {},
emits: [],
model: {},
props: {
value: {type: [String, Array]}, // v-model 绑定的Object
limit: {type: Number, default: 1}, // 控制 上传图片数量
accept: {type: String, default: undefined}, // 限制上传的文件类型
},
data() {
return {
fileList: [],
chunkSize: 1024 * 1024 * 6, // 6M 为一个切片,超过6M,则采用上传大文件的方法进行文件上传
percentage: {}, // 进度条
}
},
computed: {
action: {
get() {
return this.$getRequestUrl(this.$servers.openServer, 'tb/minio/uploadImgCompress')
}
},
previewImgs: {
get() {
return this.fileList.map(o => getMinioUrl(o.url));
},
},
hide: {
get() {
return this.fileList.length === this.limit;
}
}
},
watch: {},
created() {
this.fileList = (
this.value
? this.limit === 1 ? [{url: this.value}] : (this.value instanceof Array ? this.value : JSON.parse(this.value)).map(o => ({url: o}))
: []
).filter(o => o.url).map(({url}) => ({url, name: url.slice(url.lastIndexOf('/') + 1)})).map(o => ({...o, uid: o.name}));
},
methods: {
getMinioUrl,
onSuccess(res, file, fileList) {
this.fileList = fileList;
let imgs = this.limit === 1
? res.data.visitPath
: JSON.stringify(fileList.map(img => img.response ? img.response.data.visitPath : img.url))
console.log(imgs)
this.$emit('input', imgs);
},
handleRemove(file) {
this.fileList.splice(this.fileList.indexOf(file), 1)
let imgs = this.limit === 1
? this.fileList.length <= 0
? ''
: this.fileList.length === 1 && this.fileList[0].response
? this.fileList[0].response.data.visitPath
: this.fileList[0].url
: JSON.stringify(this.fileList.map(img => img.response ? img.response.data.visitPath : img.url))
this.$emit('input', imgs);
},
httpRequest(params) {
let {file: {size}} = params;
size > this.chunkSize ? this.uploadBigFile(params, this.chunkSize) : this.uploadFile(params)
},
uploadFile(params) {
let {file, filename, onSuccess} = params;
const formData = new FormData();
formData.append(filename, file);
const config = {
'Content-type': 'multipart/form-data',
onUploadProgress: progress => this.percentage = Math.floor(progress.loaded / progress.total * 100)
}
this.$post(this.$servers.openServer, 'tb/minio/upload', formData, config).then(onSuccess)
},
calculationPercentage(file, index, loadeds, size) {
const loaded = loadeds.filter(o => o.length > 0).map(o => o[o.length - 1]).reduce((prev, curr) => prev + curr)
this.$set(this.percentage, file.uid, Math.floor(loaded / size * 100))
},
uploadBigFile(params, chunkSize) {
let {file, filename, onSuccess} = params;
let {size, type, name} = file;
const chunkLength = Math.ceil(file.size / chunkSize)
let chunks = Array.from({length: chunkLength}).map((v, i) => file.slice(i * chunkSize, i * chunkSize + chunkSize))
let loadeds = [];
let chunkRequests = chunks.map((chunk, i) => {
const formData = new FormData();
formData.append(filename, chunk);
loadeds[i] = [];
const config = {
'Content-type': 'multipart/form-data',
onUploadProgress: progress => {
loadeds[i].push(progress.loaded)
this.calculationPercentage(file, i, loadeds, size);
}
}
return this.$post(this.$servers.openServer, 'tb/minio/upload', formData, config);
})
this.$axios.all(chunkRequests).then(res => {
let fileNames = res.map(({data: {minioPath}}) => minioPath)
const params = {fileName: name, contentType: type, fileSize: size, fileNames}
this.$post(this.$servers.openServer, 'tb/minio/merge', params).then(onSuccess)
})
},
onRemove(file, fileList) {
this.percentage = -1;
}
}
}
</script>
- s-upload-img
<style scoped lang="less">
.hide-upload {
/deep/ .el-upload {
visibility: hidden;
}
}
</style>
<template>
<div name="s-upload-img">
<el-upload
:class="{'hide-upload':hide}" list-type="picture-card" v-bind="$attrs"
:file-list="fileList" :action="action" :limit="limit" :accept="accept"
:on-success="onSuccess" :http-request="httpRequest">
<i slot="default" class="el-icon-plus"></i>
<div slot="file" slot-scope="{file}">
<el-progress v-if="percentage[file.uid] && percentage[file.uid]<100" type="circle" :percentage="percentage[file.uid]"></el-progress>
<img :src="getMinioUrl(file.url)" style="width:100%; height:auto;" alt="">
<span class="el-upload-list__item-actions">
<span class="el-upload-list__item-preview" @click="()=>this.$refs.previewImg.showViewer = true">
<i class="el-icon-zoom-in"></i>
</span>
<span class="el-upload-list__item-delete" @click="handleRemove(file)">
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</el-upload>
<el-image ref="previewImg" v-show="false" src :preview-src-list='previewImgs'></el-image>
</div>
</template>
<script>
import SUpload from "./s-upload";
export default {
name: "s-upload-img",
extends: SUpload,
props: {
accept: {type: String, default: '.jpeg,.jpg,.png'}, // 限制上传的图片类型
},
}
</script>
到了这里,关于基于element UI 实现大文件分片上传的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!