我们先来看一下el-upload可以配置哪些属性和事件。
属性action: 请求url
headers: 设置上传的请求头部
method: 设置上传请求方法
multiple: 是否支持多选文件
data: 上传时附带的额外参数
name: 上传的文件字段名
with-credentials: 支持发送cookie凭证信息
以上这些参数都是采用action的默认方式请求时使用的,如果我们使用自定义的请求方法,这些属性基本上都不会使用到。
show-file-list: 是否显示已上传文件列表
drag: 是否启用拖拽上传
accept: 接受上传的文件类型
on-preview: 点击文件列表中已上传文件时的钩子
on-remove: 文件列表移除文件时的钩子
on-success: 文件上传成功时的钩子
on-error: 文件上传失败时的钩子
on-progress: 文件上传时的钩子
on-change: 文件状态改变时的钩子,添加,上传成功和失败都会被调用
on-exceed: 当超出限制时执行的钩子
before-upload: 文件上传之前的钩子,参数为上传的文件, 若返回false或者返回 promise 且被 reject,则停止上传。
before-remove: 删除文件之前的钩子,参数为上传的文件和文件列表, 若返回 false 或者返回 promise 且被 reject,则停止删除。
file-list/v-model:file-list: 默认上传文件
list-type: 文件列表的类型,'text' | 'picture' | 'picture-card'。
auto-upload: 是否自动上传文件
http-request: 覆盖默认的 xhr 行为,允许自行实现上传文件的请求
disabled: 是否禁用上传
limit: 允许上传文件的最大数量
方法abort: 取消上传请求
submit: 手动上传文件列表
clearfiles: 清空已上传的文件列表(该方法不支持在 before-upload 中调用)
handlestart: 手动选择文件
handleremove: 手动移除文件。 file 和rawfile 已被合并。
上传图片的实现上传图片的时候我们一般都会重写http请求,不使用默认的action去请求,因此action我们一般都会设置成‘#’。
<template> <div> <el-upload action="#" :headers="headers" :list-type="listtype" :http-request="uploadaction" :on-exceed="handleexceed" :on-remove="handleremove" :before-upload="beforeupload" :on-success="uploadsuccess" :on-error="uploaderror" :on-progress="uploadprogress" :file-list="filelistcopy.data" ref="upload" :multiple="true" :limit='limit' :disabled="disabled" :data="paramdata" > <el-icon><plus /></el-icon> <template #file="{ file }"> <div> <img :src="file.url" alt="" /> <span class="el-upload-list__item-actions"> <span class="el-upload-list__item-preview" @click="handlepicturecardpreview(file)" > <el-icon><zoom-in /></el-icon> </span> <span class="el-upload-list__item-delete" @click="handleremove(file)" > <el-icon><delete /></el-icon> </span> </span> </div> </template> </el-upload> <el-dialog v-model="previewvisible"> <img w-full :src="dialogimageurl" alt="preview image" /> </el-dialog> </div></template><script>export default { name: 'uploadimg'}</script><script setup>import { delete, plus, zoomin } from '@element-plus/icons-vue';import { reactive, ref, defineprops, defineemits, computed, getcurrentinstance } from 'vue';import { elmessage } from 'element-plus';const props = defineprops({ // 允许上传文件件的最大数量 limit:{ type:number }, // 是否禁用上传 disabled:{ type:boolean, default:false }, // 文件列表类型 listtype:{ type:string, default:'picture-card' }, // 上传时携带的额外参数 paramdata: { type:string }});const emits = defineemits([]);const cns = getcurrentinstance();const globobj = cns.appcontext.config.globalproperties;const previewvisible = ref(false);const dialogimageurl = ref('');const filelistcopy = reactive({ data: []});const onece = ref(false);const mychangefile = ref('');const changefileindex = ref(-1);const uploadimgarr = reactive({ data: []});const headers = reactive({});// 预览大图const handlepicturecardpreview = (uploadfile) => { dialogimageurl.value = uploadfile.url; previewvisible.value = true;};// 移除图片const handleremove = (file, filelist) => { console.log('handleremove', handleremove); console.log('file', file); console.log('filelist', filelist); filelistcopy.data = filelistcopy.data.filter(v => v.uid !== file.uid);};// 文件上传数量限制const handleexceed = (files, filelist) => { if (props.limit) { elmessage.error(`只能上传${props.limit}张图片`); } console.log('handleexceed', handleexceed); console.log('files', files); console.log('filelist', filelist);};// 上传请求const uploadaction = (option) => { let formdata = new formdata(); const url = ''; globobj.$axios({ url: url, method: 'post', transformrequest: [function(data, headers) { // 去除post请求默认的content-type delete headers['content-type'] return data }], data: formdata, timeout: 300000 }).then(res => { elmessage.success('资产添加成功'); }).catch((err) => { console.log(err); });}// 格式大小的限制const beforeupload = (file) => { let isjpg = false, filetype = file.type.split('/')[0]; if(file.type === "image/jpeg" || file.type === "image/png") { isjpg = true; } else { isjpg = false; } const islt2m = file.size / 1024 / 1024; if (filetype != 'image' || islt2m > 2) { elmessage.error("请上传2m以内的图片文件!"); return false } return true;};// 文件上传成功时的钩子const uploadsuccess = (response, file, filelist) => { // 上传成功之后后台返回的数据 console.log('uploadsuccess', uploadsuccess);};const uploadprogress = (e, file, filelist) => { console.log('uploadprogress', uploadprogress)};const uploaderror = (err, file, filelist) => { console.log('uploaderror', uploaderror);};</script>
存在的坑一般上传文件的话请求头中的content-type: multipart/form-data;我们的需求中还需要设置文件的随机数,因此请求头需要是这样的content-type: multipart/form-data; boundary=----webkitformboundarypzslbadttrufx5fc。
下面是我遇到的问题。
问题1设置了content-type: multipart/form-data;此时请求一直没有随机数boundary=----webkitformboundarypzslbadttrufx5fc。
如果设置了全局的content-type,会发现上传接口设置multipart/form-data是不起作用的,因为没有boundary,所以上传必定失败,服务器500。
然后尝试手动添加boundary,这次错误变400了
问题2后来通过查询资料,说不用设置content-type: multipart/form-data;只要参数是formdata形式,浏览器就会自动将请求头的content-type转成content-type: multipart/form-data; boundary=----webkitformboundarypzslbadttrufx5fc。
但是我不设置的话就是默认的application/json。
于是查阅资料发现axios的transformrequest属性可以在向服务器发送请求数据之前修改请求数据,因为我们的请求在默认的post请求方式时content-type的值是application/json,需要去掉默认的值,这样浏览器就可以自动添加了。
globobj.$axios({ url: url, method: 'post', transformrequest: [function(data, headers) { // 去除post请求默认的content-type delete headers['content-type'] return data }], data: formdata, timeout: 300000 }).then(res => { elmessage.success('资产添加成功'); }).catch((err) => { console.log(err); });
问题3如果还要传其他的参数,其他的参数必须也要append进去,否则可能会报参数错误。
const formdata = new formdata();formdata.append('file', file);// 其他参数formdata.append('mailsys', mailsys);
以上就是vue3如何使用el-upload上传文件的详细内容。
