el-upload子组件上传多张图片(上传为files或base64url)

场景:

在表单页,有图片需要上传,表单的操作行按钮中有上传按钮,点击上传按钮。

弹出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.youkuaiyun.com/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) {
               

                //......省略 原来的提交到父组件的逻辑
            }
        },
 


 

### Vue3 中使用 Element UI 的 `el-upload` 组件与 Django 后端配合实现手动上传图片 #### 前端设置 为了在前端集成 `el-upload` 和 `el-form` 来完成文件上传操作,需确保安装并引入了必要的库: ```bash npm install element-plus axios vue@next ``` 创建表单组件时,定义一个用于存储待上传图像数据的对象。此对象作为双向绑定的目标,以便于收集用户输入的信息。 ```javascript // src/components/UploadImageForm.vue <template> <el-form :model="form"> <!-- 图片上传 --> <el-form-item label="上传图片" prop="image"> <el-upload ref="upload" action="" list-type="picture-card" :auto-upload="false" :on-change="handleChange" :file-list="form.imageList" > <i class="el-icon-plus"></i> </el-upload> </el-form-item> <el-button type="primary" @click="submitForm">提交</el-button> </el-form> </template> <script setup> import { reactive } from 'vue'; import axios from 'axios'; const form = reactive({ imageList: [] }); function handleChange(file, fileList) { const formData = new FormData(); fileList.forEach(f => { formData.append('images', f.raw); }); } async function submitForm() { try { let formData = new FormData(); // 将所有选中的文件加入到FormData实例中 this.$refs.upload.submit().then((files) => { files.fileList.forEach(function (item) { formData.append("images", item.raw); }); await axios.post('/api/upload/', formData, { headers: {'Content-Type': 'multipart/form-data'} }).catch(error => console.error(error)); alert('上传成功'); }); } catch (error) { console.log(error.message); } } </script> ``` 上述代码片段展示了如何利用 `el-upload` 控件来捕获用户的文件选择动作,并通过自定义事件处理器将这些文件附加到 `FormData` 对象内[^2]。 #### 后端配置 对于Django项目而言,除了常规的应用程序搭建外,还需特别注意媒体资源路径的设定以及视图函数的设计以接收来自客户端的数据流。 ##### 设置静态和多媒体文件路径 编辑项目的 settings.py 文件,指定媒体文件保存的位置及其URL前缀: ```python # myproject/settings.py MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads') ``` 这一步骤明确了服务器上实际存放用户上传资料的具体位置[^1]。 ##### 创建API接口处理上传逻辑 编写专门负责接受HTTP POST请求并将接收到的内容写入磁盘的方法: ```python from rest_framework.views import APIView from rest_framework.response import Response from django.core.files.storage import default_storage class FileUploadAPIView(APIView): def post(self, request): file_obj = request.FILES.getlist('images') saved_files = [] for img in file_obj: path = default_storage.save(img.name, img) saved_files.append(path) return Response({'message': 'Files uploaded successfully.', 'paths': saved_files}) ``` 该类继承自 DRF 提供的基础视图基类 `APIView`, 并重写了默认行为以适应特定需求——即解析 multipart/form-data 类型的消息体获取其中携带的一个多个二进制大对象(BLOB),再借助内置工具将其持久化至本地文件系统中去[^4]. 最后记得注册路由映射关系使得外部能够访问新建立的服务端点.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值