element upload提供的功能很强大,但在使用的时候,有太多参数,和事件回调需要处理,不便于重复使用,每次都还弄晕了,为了便于使用,我将Upload针对于图片上传的功能,进行了一个封装处理,所有的回调都在插件里面进行处理了,使用只需要加一个标签就可以了,支持多文件上传,删除,预览,回显,文件大小限制,文件类型限制,自定义上传方法等各种参数,有需要的朋友可以看看,如果有更好的方法和意见,欢迎留言讨论。
项目GitHub地址:https://github.com/dingh123/dh-plugin/tree/master/UploadImage
基于ElementUI二次封装的图片上传组件,支持多文件上传,直接使用v-model取值回显
在 script
中引用组件
import UploadImage from '@/components/UploadImage/index.vue';
export default {
components: {UploadImage}
}
在 template
中使用组件
<upload-image ref="uploadImage" v-model="formData.image" :limit="6" :multiple="true" description="建议上传600x600的图片,只能上传jpg/png/gif文件" />
如果动态设置回显,需要手动触发一下watchValue方法
this.formData.image = res.image;
this.$nextTick(() => {
this.$refs.uploadImage.watchValue();
});
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
multiple | Boolean | false | 是否支持多选 |
data | Object | - | 上传时附带的额外参数 |
showFileList | Boolean | true | 是否显示已上传文件列表 |
limit | Number | - | 最大允许上传个数 |
name | String | file | 设定文件域的字段名 |
accept | String | image/jpeg, image/png, image/gif | 接受上传的文件类型 |
description | String | - | 文件上传描述 |
size | Number | 5 * 1024 | 文件大小限制,单位KB,默认5MB |
httpRequest | Function | - | 自定义上传方法 |
1、【默认上传】这个方法是设置组件默认上传的方法,避免每次使用时候都需要写一个上传方法;
uploadImgRequest(f) {
let param = new FormData(); //创建form对象
param.append('file', f.file); //通过append向form对象添加数据
uploadImg(param)
.then(res => {
f.onSuccess(res);
})
.catch(() => {
f.onError();
});
},
2、【自定义上传】支持默认上传的同时也支持自定义上传方法,httpRequest
<template>
<upload-image
class="icon-image"
ref="uploadFavicon"
v-model="favicon"
:limit="1"
accept="image/x-icon"
:http-request="uploadRequestIcon"
/>
</template>
<script>
import UploadImage from '@/components/UploadImage/index.vue';
import { uploadIcon } from '@/api';
export default {
components: { UploadImage },
methods: {
/**
* 自定义上传方法,icon
*/
uploadRequestIcon(f) {
let param = new FormData(); //创建form对象
param.append('file', f.file); //通过append向form对象添加数据
uploadIcon(param)
.then(res => {
f.onSuccess(res);
})
.catch(() => {
f.onError();
});
},
},
};
</script>
UploadImage.vue
<template>
<div>
<el-upload
ref="elUpload"
action="#"
list-type="picture-card"
:data="data"
:multiple="multiple"
:limit="limit"
:fileList="fileList"
:show-file-list="showFileList"
:name="name"
:accept="accept"
:before-upload="beforeUpload"
:on-preview="handlePictureCardPreview"
:on-success="handleImageSuccess"
:on-remove="handleRemove"
:on-exceed="handleExceed"
class="upload-image"
:class="{ 'hide-upload': hideUpload }"
:http-request="httpRequestMain"
>
<div class="upload-tip">
<i class="el-icon-plus"></i>
<div class="el-upload__tip" v-if="description">
{{ description }}
</div>
</div>
</el-upload>
<el-image-viewer v-if="showViewer" :on-close="closeViewer" :url-list="viewImageUrl" />
</div>
</template>
<script>
import { uploadImg } from '@/api';
import emitter from 'element-ui/src/mixins/emitter';
import ElImageViewer from 'element-ui/packages/image/src/image-viewer';
export default {
name: 'UploadImage',
mixins: [emitter],
components: {
ElImageViewer,
},
props: {
value: {
type: String,
default: '',
},
// 是否支持多选
multiple: {
type: Boolean,
default: false,
},
// 上传时附带的额外参数
data: {
type: Object,
},
// 是否显示已上传文件列表
showFileList: {
type: Boolean,
default: true,
},
// 最大允许上传个数
limit: {
type: Number,
},
// 设定文件域的字段名
name: {
type: String,
default: 'file',
},
// 接受上传的文件类型
accept: {
type: String,
default: 'image/jpeg, image/png, image/gif',
},
// 文件上传描述
description: {
type: String,
default: '',
// default: '请上传图片,只能上传jpg/png/gif文件',
},
validateEvent: {
type: Boolean,
default: true,
},
// 文件大小限制,单位KB,默认5MB
size: {
type: Number,
default: 5 * 1024,
},
// 自定义文件上传方法
httpRequest: {
type: Function,
},
},
data() {
return {
tempUrl: '',
hideUpload: false,
fileList: [],
showViewer: false,
viewImageUrl: [],
};
},
inject: {
elForm: {
default: '',
},
elFormItem: {
default: '',
},
},
created() {
this.watchValue();
},
watch: {
value(val) {
// this.watchValue();
// console.log(val);
},
},
methods: {
httpRequestMain(f) {
this.httpRequest ? this.httpRequest(f) : this.uploadImgRequest(f);
},
watchValue() {
let valueArray = this.value ? this.value.split(',') : [];
this.fileList = valueArray.map(item => {
return {
name: item,
url: item,
};
});
this.update();
},
uploadImgRequest(f) {
let param = new FormData(); //创建form对象
param.append('file', f.file); //通过append向form对象添加数据
uploadImg(param)
.then(res => {
f.onSuccess(res);
})
.catch(() => {
f.onError();
});
},
update() {
let valueArray = this.value ? this.value.split(',') : [];
if (valueArray.length >= this.limit) {
this.hideUpload = true;
} else {
this.hideUpload = false;
}
},
emitInput(value) {
this.$emit('input', value);
this.dispatch('ElFormItem', 'el.form.change', value);
this.$nextTick(() => {
this.update();
});
},
beforeUpload(file) {
const fileMax = file.size / 1024 < this.size;
if (!fileMax) {
this.$message.error(`上传图片大小不能超过 ${this.renderSize(this.size / 1024)}!`);
}
return !!fileMax;
},
handlePictureCardPreview(file) {
this.viewImageUrl = [file.url];
this.showViewer = true;
},
closeViewer() {
this.showViewer = false;
},
handleRemove(file, fileList) {
const fileArray = fileList.map(item => {
return item.response.url;
});
this.emitInput(fileArray.join(','));
},
handleImageSuccess(res, file, fileList) {
file.url = res.url;
this.emitInput(this.value ? this.value + ',' + res.url : res.url);
},
handleExceed() {
this.$message.error(`最多上传${this.limit}张图片`);
},
clearFiles() {
this.$refs.elUpload.clearFiles();
},
renderSize(value) {
if (null == value || value == '') {
return '0 Bytes';
}
let unitArr = new Array('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
let index = 0;
let srcsize = parseFloat(value);
index = Math.floor(Math.log(srcsize) / Math.log(1024));
let size = srcsize / Math.pow(1024, index);
size = size.toFixed(2); //保留的小数位数
return size + unitArr[index];
},
},
};
</script>
<style lang="scss" scoped>
/deep/ .el-upload-list--picture-card {
display: flex;
/deep/ .el-upload-list__item {
margin: 0;
}
}
.hide-upload /deep/ .el-upload--picture-card {
display: none;
}
.upload-tip {
height: 100%;
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 10px;
}
.el-upload__tip {
line-height: 20px;
margin-top: 10px;
}
</style>