当前位置: 首页 > news >正文

element-ui upload 组件源码分享

form 导航菜单源码简单分享,主要从以下几个方面:

1、upload 组件页面结构。

2、upload 组件属性。

3、upload 组件 slot。

4、upload 组件方法。

一、组件页面结构。

二、组件属性。

2.1 action 必选参数,上传的地址,类型 string,默认无。

 XMLHttpRequest 对象的 api 地址:XMLHttpRequest - Web API | MDN

2.2 headers 设置上传的请求头部,类型 object,无默认值。

2.3 multiple 是否支持多选文件,类型 boolean,无默认值。

2.4 data 上传时附带的额外参数,类型 object,无默认值。

2.5 name 上传的文件字段名,类型 string,默认 file。

2.6 with-credentials 支持发送 cookie 凭证信息,类型 boolean,默认 false。

2.7 show-file-list 是否显示已上传文件列表,类型 boolean,默认 true。

2.8 drag 是否启用拖拽上传,类型 boolean,默认 false。

2.9 accept 接受上传的文件类型(thumbnail-mode 模式下此参数无效),类型 string,无默认值。

2.10 on-preview 点击文件列表中已上传的文件时的钩子,类型 function(file),无默认值。

2.11 on-remove 文件列表移除文件时的钩子,类型 function(file, fileList),无默认值。

2.12 on-success 文件上传成功时的钩子,类型 function(response, file, fileList),无默认值。

// on-success 回调函数主要针对于自动上传使用,调用 upload 组件默认上传方法
// 以下是使用手动上传时,on-success 回调函数的使用
<template><div><el-uploadref="uploadRef":auto-upload="false":on-change="handleAvatarChange":show-file-list="true"class="upload-avatar-wrapper"accept="image/*":action="uploadUrl":on-preview="onPreview":on-remove="onRemove":on-success="onSuccess"><!-- 显示当前已选/已上传的图片 --><div class="avatar-preview-list"><imgv-if="tempPreviews.url":src="tempPreviews.url"class="avatar"style="width:60px;height:60px;margin-right:10px;border:1px #ddd solid;object-fit: cover;"/></div><divv-if="!tempPreviews.url"class="avatar-uploader-icon"style="width:60px;height:60px;text-align:center;line-height:60px;border:1px #ddd solid;"><i class="el-icon-plus"></i></div></el-upload><el-button @click="customUpload">上传</el-button></div>
</template><script>export default {data() {return {token:'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyQ29kZSI6InN1cGVyMDAxIiwiaWF0IjoxNzQ3Mjc5NzA2LCJleHAiOjE3NDc4ODQ1MDZ9.KfSi5zAq3c45Gjv6tkH5is5LtDx_74X99bb5fR_YXPc',form: {operName: 'super001',password: '123456',avatar: '',},tempPreviews: {}, // 存储预览图片对象selectedFile: null, // 当前选择的文件serverUrl: 'http://localhost:3000',uploadUrl: '/api/user/uploadAvatar',};},methods: {onSuccess(response, file, fileList) {console.log('onSuccess response::', response);this.$message.success('上传成功');this.form.avatar = `${this.serverUrl}${response.url}`;},onRemove(file, fileList) {this.tempPreviews = {};this.selectedFile = null;},onPreview(file) {console.log('onPreview file::', file);},handleAvatarChange(file, fileList) {// 如果已经有文件被选中,则阻止继续选择if (this.selectedFile) {this.$message.warning('只能选择一个文件');return false;}const reader = new FileReader();reader.onload = (e) => {this.tempPreviews = {url: e.target.result,uid: file.uid,};};if (file.raw) {reader.readAsDataURL(file.raw);this.selectedFile = file.raw;}},customUpload() {if (!this.selectedFile) {this.$message.warning('请先选择一个文件');return;}const formData = new FormData();formData.append('avatar', this.selectedFile); // 单个文件formData.append('operName', this.form.operName);formData.append('password', this.form.password);fetch(this.uploadUrl, {method: 'POST',headers: {Authorization: `Bearer ${this.token}`,},body: formData,}).then((response) => {if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}return response.json();}).then((data) => {console.log('Success:', data);this.onSuccess(data, { raw: this.selectedFile }, [{ raw: this.selectedFile },]);this.selectedFile = null;this.tempPreviews = {};}).catch((error) => {console.error('Error:', error);this.$message.error('上传失败');});},},};
</script><style scoped>.upload-avatar-wrapper {width: 60px;height: 60px;border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;display: flex;justify-content: center;align-items: center;}.upload-avatar-wrapper:hover {border-color: #409eff;}.avatar-uploader-icon {font-size: 28px;}.avatar {width: 100%;height: 100%;object-fit: cover;}
</style>
// 自动上传,调用upload 默认的上传方法
<template><div><el-uploadref="uploadRef":auto-upload="true":on-change="handleAvatarChange":show-file-list="false"class="upload-avatar-wrapper"accept="image/*"action="/api/user/uploadAvatar"name="avatar":headers="{'Authorization': `Bearer ${token}`}":data="{operName: 'super001',password: '123456',}":multiple="false":limit="1":on-exceed="handleExceed":with-credentials="false":on-success="handleSuccess":on-error="handleError":on-remove="handleRemove"><!-- 显示当前头像 --><div class="avatar-preview"><imgv-if="form.avatar || tempPreview":src="form.avatar || tempPreview"class="avatar"style="width:60px;height:60px;margin-right:10px;border:1px #ddd solid;object-fit: cover;"/></div><!-- 触发上传按钮 --><divclass="avatar-uploader-icon"style="width:60px;height:60px;text-align:center;line-height:60px;border:1px #ddd solid;"><i class="el-icon-plus"></i></div></el-upload></div>
</template><script>export default {data() {return {token:'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyQ29kZSI6InN1cGVyMDAxIiwiaWF0IjoxNzQ3Mjc5NzA2LCJleHAiOjE3NDc4ODQ1MDZ9.KfSi5zAq3c45Gjv6tkH5is5LtDx_74X99bb5fR_YXPc',serverUrl: 'http://localhost:3000',form: {operName: 'super001',password: '123456',avatar: '', // 单个字符串存储头像URL},tempPreview: null, // 临时存放本地预览};},methods: {handleExceed(files, fileList) {this.$message.warning('只能选择一个文件');},handleAvatarChange(file, fileList) {const reader = new FileReader();reader.onload = (e) => {// 设置临时预览图this.tempPreview = e.target.result;};if (file.raw) {reader.readAsDataURL(file.raw);}},handleSuccess(response, file, fileList) {this.$message.success('上传成功');const uploadedUrl = response.url;if (uploadedUrl) {this.form.avatar = `${this.serverUrl}${uploadedUrl}`;this.tempPreview = null; // 清除临时预览图}},handleError(err, file, fileList) {console.error('Upload Error:', err);this.$message.error('上传失败');this.tempPreview = null; // 出错时清除临时预览图},handleRemove(file, fileList) {this.form.avatar = ''; // 清空 form.avatarthis.tempPreview = null; // 清除临时预览图},},};
</script><style scoped>.avatar-preview {display: flex;justify-content: flex-start;margin-bottom: 10px;}.avatar {width: 60px;height: 60px;object-fit: cover;border: 1px solid #ddd;margin-right: 10px;}.upload-avatar-wrapper {width: 60px;height: 60px;border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;display: flex;justify-content: center;align-items: center;}.upload-avatar-wrapper:hover {border-color: #409eff;}.avatar-uploader-icon {font-size: 28px;}
</style>

2.13 on-error 文件上传失败时的钩子,类型 function(err, file, fileList),无默认值。

2.14 on-progress 文件上传时的钩子,类型 function(event, file, fileList),无默认值。

// 增加上传进度条
<template><div><!-- 文件上传组件 --><el-uploadref="uploadRef":auto-upload="true":on-change="handleAvatarChange":show-file-list="false"class="upload-avatar-wrapper"accept="image/*"action="/api/user/uploadAvatar"name="avatar":headers="{'Authorization': `Bearer ${token}`}":data="{operName: 'super001',password: '123456',}":multiple="false":limit="1":on-exceed="handleExceed":with-credentials="false":on-success="handleSuccess":on-error="handleError":on-remove="handleRemove":on-progress="handleProgress"><!-- 显示当前头像 --><div class="avatar-preview"><imgv-if="form.avatar || tempPreview":src="form.avatar || tempPreview"class="avatar"style="width:60px;height:60px;margin-right:10px;border:1px #ddd solid;object-fit: cover;"/></div><!-- 触发上传按钮 --><divclass="avatar-uploader-icon"style="width:60px;height:60px;text-align:center;line-height:60px;border:1px #ddd solid;"><i class="el-icon-plus"></i></div></el-upload><!-- 进度条 --><el-progress v-if="percentage > 0" :percentage="percentage"></el-progress></div>
</template><script>export default {data() {return {token:'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyQ29kZSI6InN1cGVyMDAxIiwiaWF0IjoxNzQ3Mjc5NzA2LCJleHAiOjE3NDc4ODQ1MDZ9.KfSi5zAq3c45Gjv6tkH5is5LtDx_74X99bb5fR_YXPc', // 替换为实际的TokenserverUrl: 'http://localhost:3000',form: {operName: 'super001',password: '123456',avatar: '', // 单个字符串存储头像URL},tempPreview: null, // 临时存放本地预览percentage: 0, // 新增:用于存储上传进度百分比};},methods: {handleProgress(event, file, fileList) {// 更新进度百分比this.percentage = Math.floor(event.percent);console.log(`正在上传 ${file.name}: ${this.percentage}%`);},handleExceed(files, fileList) {this.$message.warning('只能选择一个文件');},handleAvatarChange(file, fileList) {const reader = new FileReader();reader.onload = (e) => {// 设置临时预览图this.tempPreview = e.target.result;};if (file.raw) {reader.readAsDataURL(file.raw);}},handleSuccess(response, file, fileList) {this.$message.success('上传成功');const uploadedUrl = response.url;if (uploadedUrl) {this.form.avatar = `${this.serverUrl}${uploadedUrl}`;this.tempPreview = null; // 清除临时预览图this.percentage = 100; // 完成时设置为100%setTimeout(() => {this.percentage = 0; // 成功后两秒隐藏进度条}, 2000);}},handleError(err, file, fileList) {console.error('Upload Error:', err);this.$message.error('上传失败');this.tempPreview = null; // 出错时清除临时预览图this.percentage = 0; // 错误时重置进度条},handleRemove(file, fileList) {this.form.avatar = ''; // 清空 form.avatarthis.tempPreview = null; // 清除临时预览图this.percentage = 0; // 删除文件时重置进度条},},};
</script><style scoped>.avatar-preview {display: flex;justify-content: flex-start;margin-bottom: 10px;}.avatar {width: 60px;height: 60px;object-fit: cover;border: 1px solid #ddd;margin-right: 10px;}.upload-avatar-wrapper {width: 60px;height: 60px;border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;display: flex;justify-content: center;align-items: center;}.upload-avatar-wrapper:hover {border-color: #409eff;}.avatar-uploader-icon {font-size: 28px;}
</style>

2.15 on-change 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用,类型 function(file, fileList),无默认值。

2.16 before-upload 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。类型 function(file),无默认值。

<template><div><!-- 文件上传组件 --><el-uploadref="uploadRef":auto-upload="true":on-change="handleAvatarChange":show-file-list="false"class="upload-avatar-wrapper"accept="image/*"action="/api/user/uploadAvatar"name="avatar":headers="{'Authorization': `Bearer ${token}`}":data="{operName: 'super001',password: '123456',}":multiple="false":limit="1":on-exceed="handleExceed":with-credentials="false":on-success="handleSuccess":on-error="handleError":on-remove="handleRemove":on-progress="handleProgress":before-upload="beforeUpload"><!-- 显示当前头像 --><div class="avatar-preview"><imgv-if="form.avatar || tempPreview":src="form.avatar || tempPreview"class="avatar"style="width:60px;height:60px;margin-right:10px;border:1px #ddd solid;object-fit: cover;"/></div><!-- 触发上传按钮 --><divclass="avatar-uploader-icon"style="width:60px;height:60px;text-align:center;line-height:60px;border:1px #ddd solid;"><i class="el-icon-plus"></i></div></el-upload><!-- 进度条 --><el-progress v-if="percentage > 0" :percentage="percentage"></el-progress></div>
</template><script>export default {data() {return {token:'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyQ29kZSI6InN1cGVyMDAxIiwiaWF0IjoxNzQ3Mjc5NzA2LCJleHAiOjE3NDc4ODQ1MDZ9.KfSi5zAq3c45Gjv6tkH5is5LtDx_74X99bb5fR_YXPc', // 替换为实际的TokenserverUrl: 'http://localhost:3000',form: {operName: 'super001',password: '123456',avatar: '', // 单个字符串存储头像URL},tempPreview: null, // 临时存放本地预览percentage: 0, // 新增:用于存储上传进度百分比};},methods: {beforeUpload(file) {const isJPG = file.name.endsWith('.jpg');if (!isJPG) {this.$message.error('您只能上传 JPG 格式的图片!');}return isJPG;},handleProgress(event, file, fileList) {// 更新进度百分比this.percentage = Math.floor(event.percent);console.log(`正在上传 ${file.name}: ${this.percentage}%`);},handleExceed(files, fileList) {this.$message.warning('只能选择一个文件');},handleAvatarChange(file, fileList) {const reader = new FileReader();reader.onload = (e) => {// 设置临时预览图this.tempPreview = e.target.result;};if (file.raw) {reader.readAsDataURL(file.raw);}},handleSuccess(response, file, fileList) {this.$message.success('上传成功');const uploadedUrl = response.url;if (uploadedUrl) {this.form.avatar = `${this.serverUrl}${uploadedUrl}`;this.tempPreview = null; // 清除临时预览图this.percentage = 100; // 完成时设置为100%setTimeout(() => {this.percentage = 0; // 成功后两秒隐藏进度条}, 2000);}},handleError(err, file, fileList) {console.error('Upload Error:', err);this.$message.error('上传失败');this.tempPreview = null; // 出错时清除临时预览图this.percentage = 0; // 错误时重置进度条},handleRemove(file, fileList) {this.form.avatar = ''; // 清空 form.avatarthis.tempPreview = null; // 清除临时预览图this.percentage = 0; // 删除文件时重置进度条},},};
</script><style scoped>.avatar-preview {display: flex;justify-content: flex-start;margin-bottom: 10px;}.avatar {width: 60px;height: 60px;object-fit: cover;border: 1px solid #ddd;margin-right: 10px;}.upload-avatar-wrapper {width: 60px;height: 60px;border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;display: flex;justify-content: center;align-items: center;}.upload-avatar-wrapper:hover {border-color: #409eff;}.avatar-uploader-icon {font-size: 28px;}
</style>

2.17 before-remove 删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止删除。类型 function(file, fileList),无默认值。

// before-remove 回调函数使用
<template><div><!-- 文件上传组件 --><el-uploadref="uploadRef":auto-upload="true":on-change="handleAvatarChange":show-file-list="true"class="upload-avatar-wrapper"accept="image/*"action="/api/user/uploadAvatar"name="avatar":headers="{'Authorization': `Bearer ${token}`}":data="{operName: 'super001',password: '123456',}":multiple="false":limit="1":on-exceed="handleExceed":with-credentials="false":on-success="handleSuccess":on-error="handleError":on-remove="handleRemove":on-progress="handleProgress":before-upload="beforeUpload":before-remove="beforeRemove"><!-- 显示当前头像 --><div class="avatar-preview"><imgv-if="form.avatar || tempPreview":src="form.avatar || tempPreview"class="avatar"style="width:60px;height:60px;margin-right:10px;border:1px #ddd solid;object-fit: cover;"/></div><!-- 触发上传按钮 --><divclass="avatar-uploader-icon"style="width:60px;height:60px;text-align:center;line-height:60px;border:1px #ddd solid;"><i class="el-icon-plus"></i></div></el-upload><!-- 进度条 --><el-progress v-if="percentage > 0" :percentage="percentage"></el-progress></div>
</template><script>export default {data() {return {token:'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyQ29kZSI6InN1cGVyMDAxIiwiaWF0IjoxNzQ3Mjc5NzA2LCJleHAiOjE3NDc4ODQ1MDZ9.KfSi5zAq3c45Gjv6tkH5is5LtDx_74X99bb5fR_YXPc', // 替换为实际的TokenserverUrl: 'http://localhost:3000',form: {operName: 'super001',password: '123456',avatar: '', // 单个字符串存储头像URL},tempPreview: null, // 临时存放本地预览percentage: 0, // 新增:用于存储上传进度百分比};},methods: {beforeRemove(file, fileList) {console.log('beforeRemove file::', file, 'fileList::', fileList);// 可以在此添加任何逻辑,比如询问用户是否确定删除return this.$confirm(`确定要移除 ${file.name} 吗?`, '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning',}).then(() => {// 如果用户点击了“确定”,则返回 true 允许移除return true;}).catch(() => {// 如果用户点击了“取消”,则返回 false 阻止移除return false;});},beforeUpload(file) {const isJPG = file.name.endsWith('.jpg');if (!isJPG) {this.$message.error('您只能上传 JPG 格式的图片!');return false;}return true;},handleProgress(event, file, fileList) {// 更新进度百分比this.percentage = Math.floor(event.percent);console.log(`正在上传 ${file.name}: ${this.percentage}%`);},handleExceed(files, fileList) {this.$message.warning('只能选择一个文件');},handleAvatarChange(file, fileList) {const reader = new FileReader();reader.onload = (e) => {// 设置临时预览图this.tempPreview = e.target.result;};if (file.raw) {reader.readAsDataURL(file.raw);}},handleSuccess(response, file, fileList) {this.$message.success('上传成功');const uploadedUrl = response.url;if (uploadedUrl) {this.form.avatar = `${this.serverUrl}${uploadedUrl}`;this.tempPreview = null; // 清除临时预览图this.percentage = 100; // 完成时设置为100%setTimeout(() => {this.percentage = 0; // 成功后两秒隐藏进度条}, 2000);}},handleError(err, file, fileList) {console.error('Upload Error:', err);this.$message.error('上传失败');this.tempPreview = null; // 出错时清除临时预览图this.percentage = 0; // 错误时重置进度条},handleRemove(file, fileList) {console.log('handleRemove file::', file, 'fileList::', fileList);this.form.avatar = ''; // 清空 form.avatarthis.tempPreview = null; // 清除临时预览图this.percentage = 0; // 删除文件时重置进度条},},};
</script><style scoped>.avatar-preview {display: flex;justify-content: flex-start;margin-bottom: 10px;}.avatar {width: 60px;height: 60px;object-fit: cover;border: 1px solid #ddd;margin-right: 10px;}.upload-avatar-wrapper {width: 60px;height: 60px;border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;display: flex;justify-content: center;align-items: center;}.upload-avatar-wrapper:hover {border-color: #409eff;}.avatar-uploader-icon {font-size: 28px;}
</style>

2.1 list-type 文件列表的类型,类型 string,可选值 text/picture/picture-card,默认 text。

2.19 auto-upload 是否在选取文件后立即进行上传,类型 boolean,默认 true。

2.20 file-list 上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]。类型 array,默认 []。

2.21 http-request 覆盖默认的上传行为,可以自定义上传的实现,类型 function,无默认值。

<template><div><el-uploadref="uploadRef":auto-upload="true":on-change="handleAvatarChange":show-file-list="true"class="upload-avatar-wrapper"accept="image/*":action="uploadUrl":http-request="httpRequest":on-preview="onPreview":on-remove="onRemove":on-success="onSuccess"><!-- 显示当前已选/已上传的图片 --><div class="avatar-preview-list"><imgv-if="tempPreviews.url":src="tempPreviews.url"class="avatar"style="width:60px;height:60px;margin-right:10px;border:1px #ddd solid;object-fit: cover;"/></div><divv-if="!tempPreviews.url"class="avatar-uploader-icon"style="width:60px;height:60px;text-align:center;line-height:60px;border:1px #ddd solid;"><i class="el-icon-plus"></i></div></el-upload></div>
</template><script>export default {data() {return {token:'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyQ29kZSI6InN1cGVyMDAxIiwiaWF0IjoxNzQ4MzExMjUyLCJleHAiOjE3NDg5MTYwNTJ9.B8PwiMxPfpyQELGLdBBdFrMuNxdJvpFwtsE9-6jGAWk',form: {operName: 'super001',password: '123456',avatar: '',},tempPreviews: {}, // 存储预览图片对象selectedFile: null, // 当前选择的文件serverUrl: 'http://localhost:3000',uploadUrl: '/api/user/uploadAvatar',};},methods: {onSuccess(response, file, fileList) {console.log('onSuccess response::', response);this.$message.success('上传成功');this.form.avatar = `${this.serverUrl}${response.url}`;},onRemove(file, fileList) {this.tempPreviews = {};this.selectedFile = null;},onPreview(file) {console.log('onPreview file::', file);},handleAvatarChange(file, fileList) {if (fileList.length > 1) {this.$message.warning('只能选择一个文件');fileList.splice(0, 1); // 清除多余的文件return false;}const reader = new FileReader();reader.onload = (e) => {this.tempPreviews = {url: e.target.result,uid: file.uid,};};if (file.raw) {reader.readAsDataURL(file.raw);this.selectedFile = file.raw;}},httpRequest(option) {console.log('httpRequest option::', option);const formData = new FormData();formData.append('avatar', option.file);formData.append('operName', this.form.operName);formData.append('password', this.form.password);fetch(option.action, {method: 'POST',headers: {Authorization: `Bearer ${this.token}`,},body: formData,}).then((response) => {if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}return response.json();}).then((data) => {console.log('Upload success:', data);this.form.avatar = `${this.serverUrl}${data.url}`;option.onSuccess(data); // 告诉 el-upload 成功}).catch((error) => {console.error('Upload failed:', error);this.$message.error('上传失败');option.onError(error); // 告诉 el-upload 出错});},},};
</script><style scoped>.upload-avatar-wrapper {width: 60px;height: 60px;border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;display: flex;justify-content: center;align-items: center;}.upload-avatar-wrapper:hover {border-color: #409eff;}.avatar-uploader-icon {font-size: 28px;}.avatar {width: 100%;height: 100%;object-fit: cover;}
</style>

2.22 disabled 是否禁用,类型 boolean,默认 false。

2.23 limit 最大允许上传个数,类型 number,无默认值。

2.24 on-exceed 文件超出个数限制时的钩子,类型 function(files, fileList),无默认值。

<template><div><el-uploadref="uploadRef":auto-upload="true":limit="2":multiple="true":on-change="handleAvatarChange":show-file-list="false"class="upload-avatar-wrapper"accept="image/*":action="uploadUrl":http-request="httpRequest":on-preview="onPreview":on-remove="onRemove":on-success="onSuccess":on-exceed="handleExceed"><!-- 显示当前已选/已上传的图片 --><div class="avatar-preview-list"><imgv-for="(preview, index) in tempPreviews":key="index":src="preview.url"class="avatar"style="width:60px;height:60px;margin-right:10px;border:1px #ddd solid;object-fit: cover;"/></div><divv-if="tempPreviews.length < 2"class="avatar-uploader-icon"style="width:60px;height:60px;text-align:center;line-height:60px;border:1px #ddd solid;"><i class="el-icon-plus"></i></div></el-upload></div>
</template><script>export default {data() {return {token:'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyQ29kZSI6InN1cGVyMDAxIiwiaWF0IjoxNzQ4MzExMjUyLCJleHAiOjE3NDg5MTYwNTJ9.B8PwiMxPfpyQELGLdBBdFrMuNxdJvpFwtsE9-6jGAWk',form: {operName: 'super001',password: '123456',avatar: '',},tempPreviews: [], // 存储多个预览图selectedFiles: [], // 存储选中的多个文件serverUrl: 'http://localhost:3000',uploadUrl: '/api/user/uploadAvatar',};},methods: {onSuccess(response, file, fileList) {console.log('onSuccess response::', response);this.$message.success('上传成功');this.form.avatar = `${this.serverUrl}${response.url}`;},onRemove(file, fileList) {// 从预览列表中移除对应文件this.tempPreviews = this.tempPreviews.filter((preview) => preview.uid !== file.uid);this.selectedFiles = this.selectedFiles.filter((f) => f.uid !== file.uid);},onPreview(file) {console.log('onPreview file::', file);},handleAvatarChange(file, fileList) {const limit = 2;// 如果文件总数超过限制,只保留前两个if (fileList.length > limit) {this.$message.warning('最多只能选择两个文件');this.$refs.uploadRef.clearFiles(); // 清空所有文件this.$refs.uploadRef.handleStart(fileList[0]);this.$refs.uploadRef.handleStart(fileList[1]);// 同步更新本地预览和文件数组this.tempPreviews = [];this.selectedFiles = [];// 重新添加前两个文件的预览for (let i = 0; i < 2 && i < fileList.length; i++) {const f = fileList[i];const reader = new FileReader();reader.onload = (e) => {this.tempPreviews.push({url: e.target.result,uid: f.uid,});};if (f.raw) {reader.readAsDataURL(f.raw);this.selectedFiles.push(f.raw);}}return false;}// 正常处理每个文件的预览const reader = new FileReader();reader.onload = (e) => {const preview = {url: e.target.result,uid: file.uid,};// 避免重复添加if (!this.tempPreviews.some((p) => p.uid === file.uid)) {this.tempPreviews.push(preview);}};if (file.raw) {reader.readAsDataURL(file.raw);// 避免重复保存原始文件if (!this.selectedFiles.some((f) => f.uid === file.raw.uid)) {this.selectedFiles.push(file.raw);}}},// 超出数量时提示handleExceed(files, fileList) {this.$message.warning('最多只能上传两个文件');},httpRequest(option) {console.log('httpRequest option::', option);const formData = new FormData();formData.append('avatar', option.file);formData.append('operName', this.form.operName);formData.append('password', this.form.password);fetch(option.action, {method: 'POST',headers: {Authorization: `Bearer ${this.token}`,},body: formData,}).then((response) => {if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}return response.json();}).then((data) => {console.log('Upload success:', data);this.form.avatar = `${this.serverUrl}${data.url}`;option.onSuccess(data); // 告诉 el-upload 成功}).catch((error) => {console.error('Upload failed:', error);this.$message.error('上传失败');option.onError(error); // 告诉 el-upload 出错});},},};
</script><style scoped>.upload-avatar-wrapper {width: auto;min-width: 60px;height: 60px;border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;display: flex;justify-content: center;align-items: center;flex-wrap: wrap;gap: 10px;}.upload-avatar-wrapper:hover {border-color: #409eff;}.avatar-uploader-icon {font-size: 28px;}.avatar {width: 60px;height: 60px;object-fit: cover;}
</style>

三、组件 slot 挂载。

3.1 trigger 触发文件选择框的内容。

3.2 tip 提示说明文字。

四、组件方法。

4.1 clearFiles 清空已上传的文件列表(该方法不支持在 before-upload 中调用)。

4.2 abort 取消上传请求,参数 (file: fileList 中的 file 对象)。

4.3 submit 手动上传文件列表。

相关文章:

  • C语言数据存储
  • 【b站计算机拓荒者】【2025】微信小程序开发教程 - chapter3 项目实践 - 2信息采集
  • Python打卡训练营打卡记录day38
  • 科技趋势分析系统 BBC (Big Bang of Computing)
  • 大模型(4)——Agent(基于大型语言模型的智能代理)
  • MYSQL 学习笔记
  • 解决ubuntu服务器未使用空间的分配
  • VUE npm ERR! code ERESOLVE, npm ERR! ERESOLVE could not resolve, 错误有效解决
  • 【OS安装与使用】part7-ubuntu22.04LTS 的 docker 安装与使用(实例:MTransServer服务部署)
  • GitHub 趋势日报 (2025年05月26日)
  • IDEA使用Git进行commit提交到本地git空间后撤回到commit版本之前
  • 新增 git submodule 子模块
  • 爬虫入门指南-某专利网站的专利数据查询并存储
  • 云原生技术架构技术探索
  • strace命令+SystemTap脚本排查内存问题
  • Spyglass:项目目录中的报告结构
  • 34. 自动化测试开发之使用oracle连接池实现oracle数据库操作
  • JavaScript变量宣言三剑客:var、let、const的奇幻冒险
  • 尚硅谷redis7 55-57 redis主从复制之理论简介
  • 多模态机器学习
  • 日本真人做爰无遮挡视频免费网站/网址查询注册信息查询
  • 滁州网站建设哪个好点/杭州百度快照
  • 苏州企业建站程序/沈阳seo
  • 推广网站有哪些比较好/个人网站设计方案
  • 网站建设广告图片/站长工具seo综合查询关键词
  • 云vps怎么搭建网站/线上推广如何引流