element-ui的el-upload自定义上传头像

效果图

使用element-ui的el-upload自定义上传头像:我实现这个效果的操作是,点击方框就会从本地上传一张图片,直接通过:http-request="upLoad"调用后台的接口将图片保存在服务器上,因为我这里实际上是在修改时写的代码,我进行的操作是拿到上面上传到服务器的图片地址,再调用修改接口完成图片的更换功能。(这是一个反复的过程)
在这里插入图片描述

代码部分:

代码片
<template>
    <div class="personal">
        <el-dialog title="修改个人信息" :visible.sync="dialogShow.dialogVisible" width="50%" :modal-append-to-body="false">
            <el-form ref="userInfoForm" :rules="userFormRules" :model="userInfoForm" class="user-form" label-width="100px">
                <el-form-item label="头像:" prop="avatar">
                    <el-upload
                        :action="interfaceUrl"
                        :headers="headers"
                        :http-request="upLoad"
                        :show-file-list="false"
                        class="avatar-uploader"
                        :on-success="handleAvatarSuccess"
                        :before-upload="beforeAvatarUpload"
                        name="file"
                        :file-list="fileList"
                    >
                        <img v-if="userInfoForm.avatar" :src="userInfoForm.avatar" :v-model="userInfoForm.avatar" class="avatar" />
                        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                    </el-upload>
                </el-form-item>  
                <el-form-item prop="nickName" label="昵 称:">
                    <el-input v-model="userInfoForm.nickName" placeholder="请修改昵称">
                    </el-input>
                </el-form-item>
                <el-form-item prop="sex" label="性 别:">
                    <!-- <el-input v-model="userInfoForm.sex" placeholder="请修改性别1表示男0表示女">
                    </el-input> -->
                    <!-- <template> -->
                        <el-radio v-model="userInfoForm.sex" :label="1"></el-radio>
                        <el-radio v-model="userInfoForm.sex" :label="0"></el-radio>
                    <!-- </template> -->
                </el-form-item>    
                <el-form-item prop="userName" label="用 户 名:">
                    <el-input v-model="userInfoForm.userName" placeholder="请修改用户名">
                    </el-input>
                </el-form-item>
                <el-form-item prop="realName" label="真实姓名:">
                    <el-input v-model="userInfoForm.realName" placeholder="请修改真实姓名">
                    </el-input>
                </el-form-item>
                <el-form-item prop="idCardNo" label="身份证号:">
                    <el-input v-model="userInfoForm.idCardNo" placeholder="请修改身份证号">
                    </el-input>
                </el-form-item>
                <el-form-item prop="remark" label="个性签名:">
                    <el-input v-model="userInfoForm.remark" placeholder="请修改个性签名" type="textarea" style="width:60%;">
                    </el-input>
                </el-form-item>     
                <el-form-item prop="mobilePhone" label="手机号码:">
                    <el-input v-model="userInfoForm.mobilePhone" placeholder="手机号">
                    <template slot="prepend">
                        <span class="el-icon-mobile prep-icon-span"></span>
                    </template>
                    <template slot="append">
                        <el-button @click="countDown()">{{ content }}</el-button>
                    </template>
                    </el-input>
                </el-form-item>
                <el-form-item prop="code" label="验 证 码:">
                    <el-input v-model="userInfoForm.code" placeholder="验证码">
                        <template slot="prepend">
                            <span class="el-icon-view prep-icon-span"></span>
                        </template>
                    </el-input>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
              <el-button @click="cancelModify">取 消</el-button>
              <el-button type="primary" @click="submitModify">修改</el-button>
            </div>
        </el-dialog>
    </div>
</template>

<script>
import {getToken} from '@/utils/auth'
import {baseMixin} from "@/store/app-mixin"
import {changeUserInfo} from '@/views/learn/services/personalcenter'
import {receiveVerificationCode} from '@/views/learn/services/personalcenter'
import {uploadImage} from '@/views/learn/services/personalcenter'
export default {
    props: ['dialogShow', 'userInfo'],
    mixins: [baseMixin],
    data() {
        var checkIdcard = (code) =>{
            var city = { 11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古", 21: "辽宁", 22: "吉林", 23: "黑龙江 ", 31: "上海", 32: "江苏", 33: "浙江", 34: "安徽", 35: "福建", 36: "江西", 37: "山东", 41: "河南", 42: "湖北 ", 43: "湖南", 44: "广东", 45: "广西", 46: "海南", 50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏 ", 61: "陕西", 62: "甘肃", 63: "青海", 64: "宁夏", 65: "新疆", 71: "台湾", 81: "香港", 82: "澳门", 91: "国外 " };
            var tip = "";
            var pass = true;

            if (!code || !/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i.test(code)) {
                tip = "身份证号格式错误";
                return false
            }

            if (!city[code.substr(0, 2)]) {
                tip = "地址编码错误";
                pass = false;
            }
            if (code.length == 18) {
                var sBirthday = code.substr(6, 4) + "-" + Number(code.substr(10, 2)) + "-" + Number(code.substr(12, 2));
                var d = new Date(sBirthday.replace(/-/g, "/"))
                if (sBirthday != (d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate())) {
                    //alert("非法生日");
                    return false
                }
            }
            //18位身份证需要验证最后一位校验位
            if (code.length == 18) {
                code = code.split('');
                //∑(ai×Wi)(mod 11)
                //加权因子
                var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
                //校验位
                var parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2];
                var sum = 0;
                var ai = 0;
                var wi = 0;
                for (var i = 0; i < 17; i++) {
                    ai = code[i];
                    wi = factor[i];
                    sum += ai * wi;
                }
                var last = parity[sum % 11];
                if (parity[sum % 11] != code[17]) {
                    tip = "校验位错误";
                    return false;
                }
            }
            return true;
        }
        var validatePhone = (rule, value, callback) => {
            var myreg = /^[1][2,3,4,5,7,8,9][0-9]{9}$/
            if (value === '') {
                callback(new Error('手机号不能为空'))
            } else if ( !myreg.test(value) ) {
                callback(new Error('手机号码格式不正确'))
            } else {
                callback()
            }
        }
        var validateIdCard = (rule, value, callback) => {
            if( value == '') {
                callback(new Error("身份证不能为空"))
            }else if(!checkIdcard(value)){
                callback(new Error('身份证格式验证不正确'))
            }else{
                callback();
            }
        }
        return {
            userInfoForm: {
                avatar: this.userInfo.avatar,
                email: this.userInfo.email,
                idCardNo: this.userInfo.idCardNo,//身份证号
                mobilePhone: this.userInfo.mobilePhone,
                nickName: this.userInfo.nickName,//用户昵称
                realName: this.userInfo.realName,//真实姓名
                remark: this.userInfo.remark,//说明
                sex: this.userInfo.sex,//1男,0女
                userName: this.userInfo.userName,//用户名
                code: ''
            },
            content: "发送验证码",
            totalTime: 60,
            canClick: true,
            userFormRules: {
                nickName: [
                    { required: true, message: "昵称可选填", trigger: "blur" },
                    { max: 20, message: "长度在 20 个字符以内", trigger: "change" },                    
                ],
                userName: [
                    { required: true, message: "用户名可选填", trigger: "blur" },
                    { max: 20, message: "长度在 20 个字符以内", trigger: "change" },                    
                ],
                realName: [
                    { required: true, message: "真实姓名可选填", trigger: "blur" },
                    { max: 150, message: "长度在 150 个字符以内", trigger: "change" },                    
                ],
                sex: [
                    { required: true, message: "性别可选填", trigger: "blur" },
                    { max: 1, message: "长度为1", trigger: "change" },                    
                ],
                remark: [
                    { required: true, message: "个性签名可选填", trigger: "blur" },
                    { max: 150, message: "长度在 150 个字符以内", trigger: "change" },                    
                ],
                idCardNo: [
                    { required: true, message: "身份证号可选填", trigger: "blur" },
                    { validator: validateIdCard, targger: 'blur'}                   
                ],
                mobilePhone: [
                    { validator: validatePhone, trigger: 'blur'},
                    { required: true, type: 'number', message: '手机号必须为数字'}
                ],
                code: [
                    { required: true, message: "验证码不可为空", trigger: "blur" }
                ],
            },
            interfaceUrl: '',//上传后台的接口地址
            imageUrl: '',
            headers: {
                Authorization:  getToken()
            },
            fileList: [], //上传的文件列表
        }
    },
    created() {
        this.uploadUrl()
    },
    methods: {
        countDown() {
            this.$message.warning('注意:只有修改手机号码时才需要获取验证码!!!')
            if (!this.canClick) return //改动的是这两行代码
            this.canClick = false
            this.handleSend()
            this.content = this.totalTime + "s后重新发送"
            let clock = window.setInterval(() => {
                this.totalTime--
                this.content = this.totalTime + "s后重新发送"
                if (this.totalTime < 0) {
                window.clearInterval(clock)
                this.content = "重新发送验证码"
                this.totalTime = 60
                this.canClick = true //这里重新开启
                }
            }, 1000)
        },
        handleSend() {
            this.countDown()
            receiveVerificationCode({phone: this.userInfoForm.mobilePhone}).then((res) => {
                console.log("receiveVerificationCode", res)
                if (res.code == "sys.success") {
                    this.$message.success("发送成功!!!")
                }
            })
        },
        submitModify() {
            const params = {
                userName: this.userInfoForm.userName,
                nickName: this.userInfoForm.nickName,
                realName: this.userInfoForm.realName,
                mobilePhone: this.userInfoForm.mobilePhone,
                email: this.userInfoForm.email,
                code: this.userInfoForm.code,
                avatar: this.userInfoForm.avatar,
                sex: this.userInfoForm.sex,
                idCardNo: this.userInfoForm.idCardNo
            }
            // console.log("sex",this.userInfoForm.sex)
            changeUserInfo(params).then((res) => {
                console.log("submitModify", res)
                if (res.code == "sys.success") {
                    this.$message.success("修改成功!")
                    // this.$parent.autoFresh()
                    this.dialogShow.dialogVisible = false
                }
            }).catch((err) =>{
                this.$message.error("系统内部错误,请联系管理员!")
            })
        },
        cancelModify() {
            this.dialogShow.dialogVisible = false
        },
        uploadUrl() {
            this.interfaceUrl = this.fileServerUrl()+'system/api/v1/upload'
            console.log("interfaceUrl", this.interfaceUrl)
        },
        upLoad(file) {
            console.log("aaaaaaaaaaaaa",file)
            const formData = new FormData()//通过form数据格式来传
            formData.append("file", file.file) //传文件
            console.log("bbbbbbbbbbbbb",formData)
            uploadImage(formData).then((res) => {
                console.log(res);
                console.log('上传成功')
                if (res.code === "sys.success") {
                    this.userInfoForm.avatar = this.fileServerUrl()+ res.data.fileSrc
                    const previewImage = this.userInfoForm.avatar
                    console.log("previewImage",previewImage)
                } else {
                this.$message('头像上传失败')
                }
            })            
        },
        // 点击更换头像
        handleAvatarSuccess(res, file) {
            // 这句话就是连接后台服务器的
            this.userInfoForm.avatar = URL.createObjectURL(file.raw)
        //     console.log("kkkkkkkkk111")
            console.log("handleAvatarSuccess",this.userInfoForm.avatar)
        //     console.log("kkkkkkkkk222")
        },
        beforeAvatarUpload(file) {
            const isJPG =file.type == 'image/jpeg' || file.type == 'image/png' || file.type == 'image/gif'
            const isLt2M = file.size / 1024 / 1024 < 2
            if (!isJPG) {
                this.$message.error("上传头像图片只能是 JPG/PNG/GIF 格式!")
            }
            if (!isLt2M) {
                this.$message.error("上传头像图片大小不能超过 2MB!")
            }
            return (isJPG || isPNG) && isLt2M
        }
    }
}
</script>

<style scoped>
.user-form {

}
.el-input {
    width: 60%;
}

.avatar-uploader /deep/ .el-upload {
     border: 1px dashed #d9d9d9;
     border-radius: 6px;
     background-color: #fff;
     cursor: pointer;
     position: relative;
     overflow: hidden;
     width: 180px;
     height: 180px;
   }
   .avatar-uploader .el-upload:hover {
     border-color: #409EFF;
   }
   .avatar-uploader-icon {
     font-size: 28px;
     color: #8c939d;
     width: 178px;
     height: 178px;
     line-height: 178px;
     text-align: center;
   }
   .showUploader /deep/ .el-upload-list{
     display: none;
   }
   .avatar {
     width: 178px;
     height: 178px;
     display: block;
   }  

</style>
<think>好的,我现在需要帮助用户找到关于如何使用el-upload组件来更新头像的示例或方法。首先,用户提供的引用内容里有几个相关的资源,我需要仔细看一下这些引用,看看有没有直接相关的信息。 首先看引用[1],里面提到了Vue3和TS结合el-upload实现头像上传,并且是手动上传。用户提到手动上传时没有文件上传成功或失败的钩子,所以可能需要注意这一点。示例代码中使用了action="#"和auto-upload=false,这说明文件不会自动上传,而是需要手动触发。这可能对用户有帮助,因为更新头像通常需要用户选择图片后手动确认,而不是自动上传。 引用[2]讨论的是在上传前进行图片裁剪,这对于头像上传来说非常常见,因为头像通常需要裁剪成特定尺寸或比例。虽然用户的问题可能没有提到裁剪,但结合最佳实践,可能需要在回答中提到这一点,或者用户可能需要这个功能,所以可以考虑在相关建议里加入。 引用[3]是关于自定义上传方法,用户提到官方示例的局限性,比如需要指定完整路径和添加token到headers。这可能意味着用户需要自定义上传逻辑,比如使用自己的API接口,并且添加认证信息。这对于头像上传来说很重要,因为通常需要身份验证,所以可能需要指导用户如何设置headers或使用自定义的http-request方法。 引用[4]比较了el-upload和ant design的上传组件,但用户主要关注的是el-upload,所以可能暂时不需要考虑这部分,不过可以注意是否有其他有用的信息。 引用[5]详细描述了Vue项目中使用el-upload上传图片的流程,包括后端处理、重命名、存储等步骤。这可能对用户的后端处理部分有帮助,但用户当前的问题可能更关注前端实现,但可以结合说明前后端协作的步骤。 现在,用户的问题是如何使用el-upload来更新头像,需要示例或用法。根据引用[1]中的代码,可以看到一个基本的el-upload配置,手动上传,限制上传数量,以及预览功能。但用户可能需要更具体的头像上传示例,比如只允许上传一个图片,显示当前头像,并在上传后替换。 结合这些信息,我应该整理出一个示例,包括以下几点: 1. 使用手动上传(auto-upload=false),然后通过ref触发上传。 2. 限制只能上传一个文件(limit=1),并且设置on-exceed的处理。 3. 显示头像的预览,可能使用img标签而不是默认的文件列表。 4. 自定义上传方法,可能通过http-request覆盖默认的上传行为,添加token等headers。 5. 处理上传成功和失败的回调,更新头像的显示。 同时,引用[3]中提到需要自定义上传方法,可能需要覆盖action,设置headers,所以示例中应该包括http-request的自定义函数,比如使用axios发送请求,并携带token。 另外,引用[2]提到的图片裁剪功能,可以作为优化建议,在用户上传前进行裁剪,提升体验,但用户可能不一定需要,但可以提及。 需要注意的问题包括:手动上传时如何触发上传动作,如何获取文件数据,如何显示预览图,如何处理服务器的响应,更新头像地址等。此外,还需要处理文件类型和大小的限制,比如只允许上传图片文件,限制文件大小。 可能还需要参考官方文档,确保示例中的属性和事件名称正确,比如:before-upload、on-success等是否正确使用,或者是否有变化,比如在Vue3中是否有不同的用法。根据引用[1]中的代码,使用的是:on-preview,而Vue3中可能需要使用@前缀,但用户示例中使用了v-model:file-list,这可能是在Vue3中的写法。 综上,构建一个完整的示例,包含模板部分、脚本部分,说明关键配置项,并解释每个部分的作用。同时,根据引用中的信息,确保涵盖了手动上传自定义请求、预览处理、限制条件等关键点。</think>以下是使用 `el-upload` 实现头像更新功能的完整示例和说明: --- ### 一、基础实现示例 ```vue <template> <el-upload class="avatar-uploader" action="#" :auto-upload="false" :show-file-list="false" :on-change="handleChange" :before-upload="beforeUpload" > <img v-if="avatarUrl" :src="avatarUrl" class="avatar" /> <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon> </el-upload> </template> <script setup> import { ref } from 'vue'; import { ElMessage } from 'element-plus'; const avatarUrl = ref(''); // 文件选择后触发 const handleChange = (file) => { const reader = new FileReader(); reader.onload = (e) => { avatarUrl.value = e.target.result; // 本地预览 }; reader.readAsDataURL(file.raw); uploadFile(file.raw); // 手动触发上传 }; // 手动上传逻辑 const uploadFile = (file) => { const formData = new FormData(); formData.append('avatar', file); axios.post('/api/upload-avatar', formData, { headers: { 'Authorization': 'Bearer your_token' // 添加 Token[^3][^5] } }).then(response => { avatarUrl.value = response.data.url; // 更新服务器返回的头像地址 }).catch(error => { ElMessage.error('上传失败'); }); }; // 上传前校验 const beforeUpload = (file) => { const isImage = file.type.startsWith('image/'); const isLt2M = file.size / 1024 / 1024 < 2; if (!isImage) ElMessage.error('请上传图片文件'); if (!isLt2M) ElMessage.error('图片大小需小于2MB'); return isImage && isLt2M; }; </script> <style> .avatar-uploader .avatar { width: 100px; height: 100px; border-radius: 50%; } </style> ``` --- ### 二、关键配置说明 1. **手动上传控制** - 设置 `:auto-upload="false"` 关闭自动上传[^1] - 通过 `on-change` 事件手动触发上传逻辑 2. **头像预览** - 使用 `FileReader` 读取本地文件生成预览图[^2] - 隐藏文件列表 (`:show-file-list="false"`) 3. **自定义上传请求** - 通过 `axios` 或自定义方法覆盖默认上传行为 - 添加身份验证 Token(需结合项目实际鉴权方式) 4. **校验规则** - `before-upload` 限制文件类型为图片且大小不超过 2MB --- ### 三、进阶优化建议 1. **集成图片裁剪** 引用第三方库(如 `cropperjs`)在 `before-upload` 阶段触发裁剪弹窗[^2]: ```vue <el-dialog v-model="cropVisible"> <cropper :src="tempAvatarUrl" @crop="handleCrop" /> </el-dialog> ``` 2. **多环境配置** 通过环境变量动态设置上传地址: ```js axios.post(import.meta.env.VITE_UPLOAD_URL, formData) ``` 3. **上传状态反馈** 添加进度条提示: ```js axios.post(url, formData, { onUploadProgress: (e) => { const percent = Math.round((e.loaded / e.total) * 100) } }) ``` --- §§ 相关问题 §§ 1. 如何实现头像上传后的实时更新? 2. 怎样在 el-upload 中集成图片压缩功能? 3. 如何实现多头像上传并排序?
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值