话不多说 直接上代码 首先是template层
el-upload上层div,通过自写图片样式效果,解决图片跳变问题,即不展示图片本身的file,只展示父组件传来的数据信息;
其中 :show-file-list=“false” 一定设置为false;
设置以后 :before-upload=“handleBeforeUpload” 会不生效,所以这部分逻辑在 :show-file-list="false"就不用看了;
:class="{ disUoloadSty:noneBtnImg }" 解决上传数为1的时候,不显示上传按钮问题;
:auto-upload=“false” 一般默认启用此属性,不自动上传文件,通过onchange来触发上传动作,顺便检测类型,确认上传大小等操作;
预览的时候 dialog 如果是第二层 append-to-body加上这个属性,否则蒙层会有问题;
<template>
<div class="upload">
<div class="d-flex flex-warp">
<div
v-for="(item,index) in allFileList"
:key="index"
class="picture-card-class m-r-10 m-b-10"
>
<img
:src="item.url"
alt=""
>
<div class="cover d-flex j-c-around f-s-12">
<div class="vertical">
<i
class="el-icon-zoom-in"
@click="handlePictureCardPreview(item)"
/>
</div>
<div v-if="!$attrs.disabled">
<i
class="el-icon-delete"
@click="handleRemove(item)"
/>
</div>
</div>
</div>
<el-upload
:class="{ disUoloadSty:noneBtnImg }"
list-type="picture-card"
:disabled="$attrs.disabled"
:file-list="allFileList"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:before-upload="handleBeforeUpload"
:limit="uploadOne ? 1: ''"
action="/"
:auto-upload="false"
:show-file-list="false"
:on-change="(file, fileList) => handleOtherChange(file, fileList)"
:on-exceed="handleExceed"
>
<i class="el-icon-plus" />
</el-upload>
</div>
<el-dialog
class="preview-dialog"
:visible.sync="dialogVisible"
append-to-body
>
<img
width="100%"
:src="dialogImageUrl"
alt=""
>
</el-dialog>
</div>
</template>
<script>
// 自己的上传方法
import {
uploadFile,
} from '@/api/restfulApi';
import _ from 'lodash';
import { matchType } from '@/utils/index';
export default {
props: {
// 上传文件格式限制
uploadFileTypeArr: {
type: Array,
default: () => (
['pdf', 'doc', 'docx', 'jpg', 'png', 'xlsx', 'xls']
),
},
uploadOne: {
type: Boolean,
default: false,
},
type: {
type: String,
default: 'image',
},
parameterForm: {
type: String,
default: 'Array',
},
},
data() {
return {
// 总文件信息
allFileList: [],
fileForm: {},
dialogImageUrl: '',
dialogVisible: false,
disabled: false,
};
},
computed: {
noType() {
const deepCloneList = _.cloneDeep(this.allFileList);
const noType = deepCloneList.map((item) => {
item.fileName = item.fileName.split('.')[0];
return item;
});
return noType;
},
// 动态切换样式
noneBtnImg() {
return this.uploadOne && this.allFileList.length === 1;
},
},
watch: {
//解决当前数据格式问题,可以为字符串 也可以 是数组;
'$attrs[file-list]': {
handler(val) {
const value = this.$attrs['file-list'];
// 处理数据信息,如果图片为数据,采用这种初始化
if (this.parameterForm === 'Array' && value.length) {
this.allFileList = value.map((item) => {
item.url = item.fileUrl;
return item;
});
}
if (this.parameterForm === 'String' && value) {
// 如果数据是字符串采用split+,处理。
const list = value.split(',');
this.allFileList = list.map((item) => {
const obj = {};
obj.fileName = item;
obj.fileId = item;
obj.url = this.getUrl(item);
return obj;
});
}
},
immediate: true,
},
},
methods: {
/**
* 解决只上传一个提示,且已经有一个图片的情况下的问题
*/
handleBeforeUpload(file) {
const fileName = file.name.split('.')[0];
const splitIndex = file.name.lastIndexOf('.');
const type = file.name.substring(splitIndex + 1, file.name.length).toLowerCase();
const uploadOneflag = this.uploadOne && this.allFileList.length === 1;
const fileSizeFlag = file.size > 1024 * 1024 * 300;
const typeFlag = !this.uploadFileTypeArr.includes(type);
const nameFlag = this.noType.some(ele => ele.fileName === fileName);
console.log(uploadOneflag, fileSizeFlag, typeFlag, nameFlag);
if (uploadOneflag) {
this.$message.error('限制文件上传为1张');
}
// 文件超过大小进行提示
if (fileSizeFlag) {
this.$message.warning('上传文件超过300M,请联系管理员!');
}
// 判断文件类型,非指定类型禁止上传
if (typeFlag) {
this.$message({
type: 'warning',
message: `禁止上传该种类型文件,支持上传文件类型:${this.uploadFileTypeArr.join(' ')}`,
});
}
if (nameFlag) {
this.$message.error(`${fileName}文件重复上传!`);
}
return !(uploadOneflag || fileSizeFlag || typeFlag || nameFlag);
},
/**
* 删除逻辑,暂时只考虑当前假删情况,可以记录删除id最后保存的时候,一起提交。
*/
handleRemove(file, fileList) {
const ind = this.allFileList.findIndex(ele => ele.fileName === file.fileName);
this.allFileList.splice(ind, 1);
this.handelUpdateVal();
},
handleExceed() {
this.$message.warning('当前限制上传 1 个文件');
},
/**
* 查看预览图片信息
*/
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
// 上传成功后往addFileList里面插入一个新文件
handleOtherChange(file, fileList) {
const fileName = file.name.split('.')[0];
const allFilter = this.noType.some(ele => ele.fileName === fileName);
if (allFilter) {
const index = fileList.findIndex(item => item.fileName === fileName);
fileList.splice(index, 1);
this.$message.error(`${fileName}文件重复上传!`);
return;
}
// 文件超过大小进行提示
if (file.size > 1024 * 1024 * 300) {
this.$message.warning('上传文件超过300M,请联系管理员!');
return;
}
this.handleChange(file, fileList);
},
// 上传状态时 || 文件改变时
handleChange(file, fileList) {
// 判断文件类型,非指定类型禁止上传
const splitIndex = file.name.lastIndexOf('.');
const type = file.name.substring(splitIndex + 1, file.name.length).toLowerCase();
// const uploadFileTypeArr = ['pdf', 'doc', 'docx', 'jpg', 'png', 'xlsx', 'xls'];
if (this.uploadFileTypeArr.includes(type)) {
this.fileForm.file = file.raw;
const i = file.name.lastIndexOf('.');
this.fileForm.fileName = file.name.substring(0, i);
this.uploadFile();
} else {
const index = fileList.findIndex(item => item.name === file.name);
// 删除当前选择的文件,使再次上传可以进行
fileList.splice(index, 1);
this.$message({
type: 'warning',
message: `禁止上传该种类型文件,支持上传文件类型:${this.uploadFileTypeArr.join(' ')}`,
});
}
},
/**
* 拼接URL方法
*/
getUrl(fileId) {
return `${process.env.VUE_APP_FILE}/space/${fileId}/preview`;
},
// 上传文件
uploadFile() {
const formData = new FormData();
Object.keys(this.fileForm).forEach((item) => {
formData.append(item, this.fileForm[item]);
});
// 调上传文件的接口。上传到文件服务器获取文件id和name
uploadFile(formData).then((res) => {
const fileId = res.id;
const fileName = res.originalName;
const type = matchType(fileName);
const obj = {
fileId,
fileName,
type,
valid: -1,
src: type,
url: this.getUrl(fileId),
};
if (this.uploadOne) {
this.allFileList = [];
this.allFileList.push(obj);
} else {
this.allFileList.push(obj);
}
this.handelUpdateVal();
})
.catch(() => {})
.finally(() => {
this.fileLoading = false;
});
},
// 处理传给父组件的值,并更新父组件的值
handelUpdateVal() {
let fileList = null;
if (this.parameterForm === 'Array') {
fileList = [];
this.allFileList.forEach((item) => {
fileList.push({ fileId: item.fileId, fileName: item.fileName, fileUrl: item.url });
});
}
if (this.parameterForm === 'String') {
const newList = this.allFileList.map(item => item.fileId);
fileList = newList.join(',');
}
this.$emit('uploadVal', fileList);
},
},
};
export const matchType = (fileName) => {
// 后缀获取
let suffix = '';
// 获取类型结果
let result = '';
try {
const flieArr = fileName.split('.');
suffix = flieArr[flieArr.length - 1].toLowerCase();
} catch (err) {
suffix = '';
}
// fileName无后缀返回 false
if (!suffix) {
result = false;
return result;
}
// 图片格式
const imglist = ['png', 'jpg', 'jpeg', 'gif'];
// 进行图片匹配
result = imglist.some(item => item === suffix);
if (result) {
result = 'image';
return result;
}
// 匹配txt
// const txtlist = ['txt'];
// result = txtlist.some(item => item === suffix);
// if (result) {
// result = 'txt';
// return result;
// }
// 匹配 excel
const excelist = ['xls', 'xlsx'];
result = excelist.some(item => item === suffix);
if (result) {
result = 'excel';
return result;
}
// 匹配 word
const wordlist = ['doc', 'docx'];
result = wordlist.some(item => item === suffix);
if (result) {
result = 'word';
return result;
}
// 匹配 pdf
const pdflist = ['pdf'];
result = pdflist.some(item => item === suffix);
if (result) {
result = 'pdf';
return result;
}
// 匹配 ppt
const pptlist = ['ppt', 'pptx'];
result = pptlist.some(item => item === suffix);
if (result) {
result = 'ppt';
return result;
}
// 匹配 视频
// const videolist = ['mp4', 'm2v', 'mkv'];
// result = videolist.some(item => item === suffix);
// if (result) {
// result = 'video';
// return result;
// }
// 匹配 音频
// const radiolist = ['mp3', 'wav', 'wmv'];
// result = radiolist.some(item => item === suffix);
// if (result) {
// result = 'radio';
// return result;
// }
// 匹配 压缩包
const zipList = ['zip', 'rar'];
result = zipList.some(item => item === suffix);
if (result) {
result = 'zip';
return result;
}
// 匹配 视频
const videoList = ['mp4', 'avi'];
result = videoList.some(item => item === suffix);
if (result) {
result = 'video';
return result;
}
// 其他 文件类型
result = 'other';
return result;
};
</script>
<style lang="scss" scoped>
.upload {
// 默认图片展示样式,从el-upload扒过来的
.picture-card-class {
background-color: #fbfdff;
border-radius: 6px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 148px;
height: 148px;
cursor: pointer;
line-height: 146px;
vertical-align: top;
position: relative;
img {
width: 100%;
height: 100%;
object-fit: contain;
border-radius: 6px;
border: 1px solid #ffffff;
}
// 这部分是鼠标移动 图片显示蒙层的方法,在图片div上附着一层div,平时透明度为0,指上后显示0.7
.cover {
top: 0px;
width: 100%;
height: 100%;
text-align: center;
position: absolute;
border-radius: 6px;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
}
/* 鼠标hover,显示遮罩,设置过渡时间 */
.cover:hover {
transition: all 0.5s;
color: #ffffff;
width: 100%;
height: 100%;
opacity: 0.7;
}
}
}
</style>
<style lang="scss">
.disUoloadSty .el-upload--picture-card {
display:none; /* 文件上传隐藏 */
}
</style>
以上就是el-upload我的一些封装小建议,感觉还是不够好,只是凑合能用。