场景:
在表单页,有图片需要上传,表单的操作行按钮中有上传按钮,点击上传按钮。
弹出el-dialog进行图片的上传,可以上传多张图片。
由于多个表单页都有上传多张图片的操作,因此将上传多图的el-upload定义为公共的子组件。
效果如图:
util.js图片转base64
使用到的工具js,file转url
util.js图片转base64
// 转base64 el-upload上传的file 不能直接用,要用file.raw
// 文件对象转base64
export function getBase64Url (file) {
return new Promise ((resolve,reject) =>{
const reader = new FileReader(); //实例化文件读取对象
reader.readAsDataURL(file.raw); //将文件读取为 DataURL,也就是base64编码
reader.onload = function () {
resolve(reader)
}
reader.onerror = function (error) {
reject(error)
}
})
}
父组件代码
<el-dialog :visible.sync="showUploadDialog" :modal="false" title="上传图片" width="30%">
<div style="width:80%;height:80%;justify-content:center;align-items:center;text-align:center;display:flex">
<div style="margin-bottom:20px;" >
<upload-many ref="imgUpload" :data="getChildParam('1','正面照')" @getUploadChildData="getUploadChildData"></upload-many >
<el-button type="primary" style="margin-top:10px" @click="uploadRouteImgList" size="mini">提交图片</el-button>
</div>
</div>
</el-dialog>
//定义的data 省略样式。。。。
showUploadDialog:false,//默认false 点击上传 设置为true
uploadRowObj:{},//要上传的对象
// methods 方法 省略样式。。。。
getChildParam(type,title){
var obj = new Object();
obj.type = type;
obj.title = title;
// 当子组件需要回显已经有的图片时,应该给fileList赋值
obj.fileList =[];
// 模拟赋值 用于回显
// 假设 this.dbImgUrlList 这是数据库返回的base64 url 算有base64前缀
if(this.dbImgUrlList.length>0){
for(var i=0;i<this.dbImgUrlList.length;i++){
obj.fileList.push({id:i,url:this.dbImgUrlList[i],name:'img'+i+'.png'})
}
}
obj.commonImgList=[];
return obj;
},
//接收子组件上传的base64格式的图片url,赋值给想传给后端的对象
getUploadChildData(obj){
// 这个是files
this.uploadRowObj.routeImgList = obj.commonImgList;
// 这个是每张图片的base64url 数组
this.uploadRowObj.imgUrlArr = obj.imgUrlArr ;
},
//下面写了两种方法,可按需用其中一种
async uploadRouteImgList (){
if(this.uploadRowObj.routeImgList.length>0){
// 第一种 上传files到后端 后端接收为 @RequestParam("id") String id,@RequestParam("files") MultipartFile[] files
let formData = new FormData();
this.uploadRowObj.routeImgList.forEach(file=>{
formData.append("files",file);
})
formData.append("id", this.uploadRowObj.id);
const {code,message,data} = await uploadImg(formData)
if(code === '0'){
this.$message.success("上传成功");
this.showUploadDialog = false;
}
// 第二种 上传的是对象 对象含id和base64Url的数组 (在子组件中 url去除了base64标识的前缀)
const {code,message,data} = await uploadImg(this.uploadRowObj)
if(code === '0'){
this.$message.success("上传成功");
this.showUploadDialog = false;
}
}else{
this.$message.error("上传图片不能为空")
}
}
子组件代码
<template>
<div>
<!-- 上传多张图片的公共组件 limit可以子组件动态传不同的值过来 :file-list="data.fileList" 可以回显-->
<el-upload action="#"
accept="image/**"
:limit="10" :multiple="true" :auto-upload="false"
list-type="picture-card"
:file-list="data.fileList"
:on-change="changeUpload"
:before-upload="handleBeforeUpload"
:on-remove="imgRemove"
:show-file-list="true"
>
<i class="el-icon-plus"></i>
</el-upload>
</div>
</template>
<script>
import {getBase64Url} from '@/api/utils.js'
export default {
name:"upload",
props:{
data:{
type: Object,
default:()=>{return {} }
},
},
data(){
return {
fileList:[],
imageList:[],
hideUpload:false,
imgVisible:false,
imgUrl:'',
onChangeImgUrl:'',
type:'',
imgUrlArr:[],
}
},
mounted(){
},
methods:{
//上传基本校验
handleBeforeUpload(file,type){
var img = file.name.substring(file.name.lastIndexOf('.') + 1)
const suffix = img === 'jpg'
const suffix2 = img === 'png'
const suffix3 = img === 'jpeg'
const isLt1M = file.size / 1024 / 1024 < 1;
if (!suffix && !suffix2 && !suffix3) {
this.$message.error("只能上传图片!");
return false
}
// 可以限制图片的大小
if (!isLt1M) {
this.$message.error('上传图片大小不能超过 1MB!');
}
return suffix || suffix2 || suffix3
},
//上传后 删除
async imgRemove(file ,fileList){
var parentObj = this.data;
//删除后更新了传给父组件的图片file集合
parentObj.commonImgList= fileList;
this.imgUrlArr =[];
//删除后更新了传给父组件的图片base64url集合
for (let fileTemp of fileList) {
// 父组件如果传了回显的list
if(!fileTemp.raw){//这是回显的获取base64 url
var res = fileTemp.url.replace(/^data:image\/\w+;base64/,"");
this.imgUrlArr.push(res);
}else{// 这是刚刚上传的获取base64 url
const response = await getBase64Url(fileTemp);
var res = response.result;
res = res.replace(/^data:image\/\w+;base64/,"");
this.imgUrlArr.push(res);
}
}
parentObj.imgUrlArr = this.imgUrlArr;
// 传给父组件方法
this.$emit("getUploadchildData", parentObj);
},
//上传控件的改变事件 提交到父组件
async changeUpload(file, fileList){
var parentObj = this.data;
//删除后更新了传给父组件的图片file集合
parentObj.commonImgList= fileList;
this.imgUrlArr =[];
//多张图片都转base64 这是需要base64的情况下
for (let fileTemp of fileList) {
// 父组件如果传了回显的list
if(!fileTemp.raw){//这是回显的获取base64 url
var res = fileTemp.url.replace(/^data:image\/\w+;base64/,"");
this.imgUrlArr.push(res);
}else{// 这是刚刚上传的获取base64 url
const response = await getBase64Url(fileTemp);
var res = response.result;
res = res.replace(/^data:image\/\w+;base64/,"");
this.imgUrlArr.push(res);
}
}
// 所有图片的base64 url集合
parentObj.imgUrlArr = this.imgUrlArr;
this.$emit("getUploadchildData", parentObj);
}
}
}
</script>
<style >
.img{
width: 60%;
height: 80;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
</style>
上面的一个上传框,一个框一个框的上传一张图没有问题,后面发下一个框去选多张图片的时候有问题。出现了一个框选三张图,最后传到父组件变成了9张图。需要控制一下
后面参考用的下面文章这个加了下处理就行了。
https://blog.csdn.net/qq_33270001/article/details/114490955
我子组件修改的代码块
我的子组件参考进行了修改
1、el-upload加name
<el-upload :name="uploadId" ...>
2、data中添加了三个参数
data() {
return {
//...... 省略其他 加了下面三个参数
uploadId: Math.random().toString(36).substr(2).toLocaleUpperCase(),
uploadFiles: [], //待上传的文件列表
fileTotal: 0 //上传文件总数
};
},
3、方法中修改
/**
* 文件上传change
*/
handleChange(file, fileList) {
//获取添加文件进来的状态
(file.status == 'ready') && this.uploadFiles.push(file.raw);
//获取原始文件的个数
this.fileTotal = document.getElementsByName(this.uploadId)[0].files.length;
//如果原始文件和upload的个数相同的时候就说明已经添加完了,可以触发上传的方法了
// 我的子组件是一次上传多张,也可以一个框一个框的上传一张 因此还有个判断
if (this.uploadFiles.length === this.fileTotal || this.fileTotal<this.uploadFiles.length) {
//......省略 原来的提交到父组件的逻辑
}
},