vue element 封装上传组件(图片、文件)
vue element 封装上传组件(图片、文件)
·
1、新建封装组件components/upload.vue
<template>
<div class="uploadImgBox">
<el-upload v-bind="localOptions" action="" ref="upload" :disabled="localDisabled" :uploadText="uploadText"
:show-file-list="showFileList" :file-list="localFileList" :http-request="httpRequest" :on-exceed="handleExceed"
:on-preview="handlePictureCardPreview" :on-remove="handleRemove" :before-upload="beforeUpload"
:on-change="handleChange" :class="{hide: uploadHide}">
<!-- :before-remove="beforeRemove" -->
<el-button v-if="localOptions.listType === 'text'" size="small" type="primary" icon="el-icon-upload2">{{uploadText
|| '上传文件'}}</el-button>
<i v-else class="el-icon-plus"></i>
</el-upload>
<el-dialog v-if="localOptions.listType === 'picture-card'" class="preview-dialog" :visible.sync="visible">
<img :src="previewUrl" style="z-index: 9 !important;" />
</el-dialog>
</div>
</template>
<script>
/**
* 将图片字符串转换为数组(上传组件专用)
*/
const stringToFileList = str => {
let list = [];
if (typeof str === "string" && str) {
list = str.split(",").map((url, i) => {
const name = url.split("/").pop();
const uid = name.split(".")[0] + i;
return { url, name, uid };
});
}
return list;
};
// 接口 oss签名
import { goodDevelopOssPolicy } from "@/api/goods.js";
import $request from "@/api/axios";
export default {
props: {
disabled: {
type: Boolean,
default: false
},
uploadOptions: {
type: Object,
default: () => ({})
},
fileList: {
type: [Array, String],
default: () => []
},
uploadText: {
type: String,
default: ''
},
showFileList: {
type: Boolean,
default: true
},
},
data() {
return {
previewUrl: "",
visible: false,
localFileList: []
};
},
computed: {
localDisabled() {
return this.disabled || this.localOptions.disabled;
},
localOptions() {
let obj = {
// 上传列表的内建样式: text/ picture/ picture-card
listType: "text",
// 一次上传多个
multiple: false,
// 显示列表
showUploadList: true,
// 默认列表最大数量
limit: 1,
// 图片大小:M
size: 1.5,
// 上传类型校验
type: null,
// 组件model的参数
key: null,
disabled: false,
// 文件名参数
// hasFileName: false,
// 隐藏按钮,即只展示列表
hiddenBtn: false,
// 只允许图片上传
onlyImage: null
};
const item = JSON.parse(JSON.stringify(this.uploadOptions));
// delete item.type;
delete item.data;
// 当设置为图片时,默认先设置1个
if (item.listType === "picture-card" && item.limit === 1) {
obj.limit = 1;
obj.onlyImage = true;
}
Object.assign(obj, item);
return obj;
},
uploadHide() {
return this.localFileList.length === this.localOptions.limit;
}
},
watch: {
fileList: {
handler(list) {
if (Array.isArray(list)) {
this.localFileList = list;
} else {
this.localFileList = stringToFileList(list);
Object.assign(this.localFileList, stringToFileList(list));
}
},
deep: true,
immediate: true
}
},
methods: {
// 改变
handleChange(file, fileList) {
if (file.raw.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.raw.type === 'application/vnd.ms-excel' || file.raw.type === 'application/pdf') {
if (this.$refs['upload'].elForm) {
this.$refs['upload'].elForm.clearValidate()
}
}
},
// 自定义接口
httpRequest(data) {
const { localOptions: { key, limit }, $message: { success, error } } = this, file = data.file;
// 转义上传文件名不能被识别
let params = { dir: "common" }, fileName = file.name.replace(/[\+,#,$,?,@,(),;,:,%]/g, "_");
// fileName = encodeURIComponent(file.name)
goodDevelopOssPolicy(params).then(res => {
let url = "xxxxxxxxxxxxxxxxxxxxxxxxx"; // 上传阿里云的接口
let idx = fileName.indexOf(".");
let ossData = new FormData();
let keyValue = fileName.substr(0, idx) + new Date().getTime() + fileName.substr(idx);
const newFile = {
uid: file.uid,
name: file.name,
size: file.size,
url: ""
};
ossData.append("ossaccessKeyId", res.accessid);
ossData.append("key", "common/" + keyValue);
ossData.append("policy", res.policy);
ossData.append("signature", res.signature);
ossData.append("dir", res.dir);
ossData.append("host", url);
ossData.append("file", file);
$request({
url,
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
Authorization: sessionStorage.getItem("Cookie")
},
data: ossData
}).then(() => {
newFile.url = `${url}/${params.dir}/${keyValue}`;
this.localFileList = limit === 1 ? [newFile] : [...this.localFileList, newFile];
this.loading = false;
this.$emit("upload-success", {
file: newFile,
fileList: this.localFileList,
key
});
});
})
},
// 超出限制
handleExceed(files, fileList) {
const {
localOptions: { limit },
$message: { warning }
} = this;
warning(`当前限制选择 ${limit} 个文件,本次选择了 ${files.length
} 个文件,共选择了 ${files.length + fileList.length} 个文件`
);
},
// 点击预览图片
handlePictureCardPreview(file) {
this.visible = true;
this.previewUrl = file && file.url;
},
// 删除上传图片
handleRemove(file, fileList) {
if (file.status === 'success') {
const index = this.localFileList.indexOf(file);
const newFileList = this.localFileList.slice();
newFileList.splice(index, 1);
this.localFileList = newFileList;
this.$emit("upload-success", {
file,
fileList: newFileList,
key: this.localOptions.key
});
}
},
// 上传之前
beforeUpload(file, fileList) {
// 限制上传文件类型与大小
const isImg = file.type === 'image/jpeg' || file.type === 'image/jpg' || file.type === 'image/png' || file.type === 'image/bmp';
if(this.localOptions.listType === 'picture-card') {
if (!isImg) {
this.$message.error('上传图片格式为.jpg/.png/.jpeg/.bmp');
return false
}
}
const isFile = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.type === 'application/vnd.ms-excel' || file.type === 'application/pdf';
if(this.localOptions.listType === 'text') {
if (!isFile) {
this.$message.error('上传文件格式为.pdf/.xls/.xlsx');
return false
}
}
const isLt30M = (file.size / 1024 / 1024) < 30;
if (!isLt30M) {
this.$message.error('上传文件大小不能超过 30MB!');
return false
}
},
// 移除之前
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name}?`);
}
}
};
</script>
<style lang="less" scoped>
//去除动画
.el-list-enter-active,
.el-list-leave-active {
transition: all 0s;
}
/deep/.el-upload {
position: relative;
.el-icon-plus {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
/deep/.el-upload--picture-card {
background-color: #fbfdff;
border: 1px dashed #c0ccda;
border-radius: 6px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 64px;
height: 64px;
cursor: pointer;
line-height: 98px;
vertical-align: top;
}
/deep/.el-upload-list--picture-card .el-upload-list__item {
overflow: hidden;
background-color: #fff;
border: 1px solid #c0ccda;
border-radius: 6px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 64px;
height: 64px;
margin: 0 8px 8px 0;
display: inline-block;
}
/deep/.el-dialog {
max-width: 80vh;
max-height: 80vh;
.el-dialog__header {
display: none;
}
}
/deep/.hide .el-upload--picture-card {
display: none;
}
</style>
2、在使用上传功能的地方引入封装组件
<script>
// 上传文件
import upload from '@/components/upload.vue'
export default {
components: {
// 上传文件
upload,
},
data(){
return {}
}
}
</script>
3、使用
// 单图上传 listType:'text'上传文件,listType:'picture-card'上传图片,listType:文件类型,limit:限制上传数量, key: 唯一值
<template v-slot:img="scope">
<upload :upload-options="{listType: 'picture-card', limit: 1, key: scope.row.key}"
:file-list="scope.row.img" @upload-success="handleFileUrl">
</upload>
</template>
// 赋值 this.ruleForm.imgData
handleFileUrl(data) {
this.ruleForm.imgData.forEach((item, index) => {
if(item.key == data.key) {
this.ruleForm.imgData[index].img = (data && data.fileList && data.fileList[0] &&
data.fileList[0].url) || ""
}
})
},
// 多图上传 listType:文件类型,limit:限制上传数量, multiple: 允许多张上传
<upload :upload-options="{listType: 'picture-card', limit: 10, multiple: true}"
:file-list="ruleForm.img" @upload-success="handleImgPath">
</upload>
// 赋值 this.ruleForm.imgStr
handleImgPath(data) {
let imgArr = []
data && data.fileList.forEach(item => {
imgArr.push(item.url)
})
this.ruleForm.imgStr = imgArr.toString()
},
4、效果展示
单图展示:
更多推荐
已为社区贡献1条内容
所有评论(0)