基于elemenui+vue的上传头像加裁剪功能

mac2025-08-07  7

npm install vue-cropper //安装 import { VueCropper } from ‘vue-cropper’ //导入 components: { //注册 VueCropper, },

<el-form :model="form" label-width="80px" class="input-dialog-form" size="small" style="margin-top:20px;"> <el-form-item label="头像"> <div class="avatar-uploader"> <label class="el-upload el-upload--text" for="uploads"> <img v-if="form.avatar" :src="form.avatar_path" class="avatar"> <div v-else class="avatar-uploader-icon"> <div class="upload-icon avatar-upload_icon"></div> </div> </label> <input type="file" id="uploads" style="position:absolute; clip:rect(0 0 0 0);" accept="image/png, image/jpeg, image/gif, image/jpg" @change="uploadImg($event)"> </div> </el-form-item> <div class="save-form-button"> <el-button size="small" type="primary" :loading="saveLoading" @click="saveUserInfo">保 存</el-button> </div> //裁剪图片 <el-dialog title="图片裁剪" :visible.sync="dialogCropper" class="avatar-cropper"> <div> <vueCropper style="height:320px;" ref="cropper" :img="option.img" :outputSize="option.size" :outputType="option.outputSize" :autoCrop="option.autoCrop" :autoCropWidth="option.autoCropWidth" :autoCropHeight="option.autoCropHeight" :fixedBox="option.fixedBox" :info="option.info" @realTime="realTime" ></vueCropper> <div style="margin:10px 0px;">头像预览:</div> <div class="show-preview" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden'}"> <div :style="previews.div"> <img :src="previews.url" :style="previews.img"> </div> </div> <div class="show-preview preview-style_1" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden'}"> <div :style="previews.div"> <img :src="previews.url" :style="previews.img"> </div> </div> <div class="show-preview preview-style_2" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden'}"> <div :style="previews.div"> <img :src="previews.url" :style="previews.img"> </div> </div> </div> <span slot="footer" class="dialog-footer"> <el-button @click="dialogCropper = false">取 消</el-button> <el-button type="primary" :loading="uploadLoading" @click="finishImg">确 定</el-button> </span> </el-dialog>

js部分

script> import { VueCropper } from 'vue-cropper'; export default { name: "sys_user_center", components: { VueCropper }, data() { return { //用户信息编辑 saveLoading: false, form: { id: 0, type: "", name: "", sex: "", code: "", mobile: "", nick_name: "", avatar: "", avatar_path: "", }, //上传图片 headers: { "Authorization": "Bearer " + localStorage.getItem("lsp_token") }, accept: "image/*", upload_data: { upload_type: "formData", }, //上传图片裁剪 dialogCropper: false, uploadLoading: false, previews: {}, option: { img: "",//裁剪图片的地址 size: 1, outputSize: "png",//裁剪生成图片的质量 autoCrop: true,//是否默认生成截图框 autoCropWidth: "180",//默认生成截图框的宽度 autoCropHeight: "180", fixedBox: true,//固定截图框的大小不允许改变 info: false,//裁剪框的大小信息 }, canMove: true, original: false, canMoveBox: true, autoCrop: true, autoCropWidth: 200, autoCropHeight: 200, fixedBox: true } }, watch: { dialogCropper(val){//监听dialog的显示或者隐藏 let vue = this; if(!val){//取消上传 vue.cancelUpload(); } } }, methods: { //获取用户信息 async getUserInfo(){ let vue = this; let res = await vue.$api.home.user(); let data = res.data; vue.userInit(data.base) }, //保存用户信息 async saveUserInfo(){ let vue = this; if(vue.form.mobile.trim() == ""){ vue.$message({type: 'warning', message: '请输入手机号'}); return false; } let params = { mobile: vue.form.mobile, nick_name: vue.form.nick_name, avatar: vue.form.avatar, } vue.saveLoading = true; let res = await vue.$api.home.user(params, "put", "personal"); vue.$message({ type: res.code == 0 ? 'success' : 'error', message: res.message }); vue.saveLoading = false; }, userInit(val = null){ let vue = this; vue.form = { id: val ? val.user_id : 0, type: val ? val.type_name : "", name: val ? val.real_name : "", sex: val ? val.sex_name : "", code: val ? val.user_code : "", mobile: val ? val.mobile : "", nick_name: val ? val.nick_name : "", avatar: val ? val.avatar : "", avatar_path: val ? val.avatar_path : "", } }, //选择本地图片 uploadImg(e) { var vue = this; var file = e.target.files[0]; if (!/\.(jpg|jpeg|png|bmp|JPG|PNG)$/.test(e.target.value)) { vue.$message({message:'图片类型必须是jpeg,jpg,png,bmp中的一种', type:'warning'}); return false; } var reader = new FileReader(); reader.onload =(e) => {//监听图片上传成功事件 let data; if (typeof e.target.result === 'object') { // 把Array Buffer转化为blob 如果是base64不需要 data = window.URL.createObjectURL(new Blob([e.target.result])) }else { data = e.target.result } vue.option.img = data; ***//重要*** vue.dialogCropper = true; } // 转化为base64 reader.readAsDataURL(file) // 转化为blob //reader.readAsArrayBuffer(file); }, compress(img) {//canvas画图 压缩 返回 let canvas = document.createElement("canvas"), ctx = canvas.getContext("2d"), initSize = img.src.length, width = img.width, height = img.height; canvas.width = width canvas.height = height // 铺底色 ctx.fillStyle = "#fff" ctx.fillRect(0, 0, canvas.width, canvas.height) ctx.drawImage(img, 0, 0, width, height) //进行压缩 let ndata = canvas.toDataURL("image/jpeg", 0.8) return ndata }, // //上传头像 finishImg(type) { let vue = this; let formData = new FormData(); //获取截图的base64 数据 vue.$refs.cropper.getCropData((data) => { let img = new Image(); img.src = data; img.onload = function(){ let data = vue.compress(img); vue.uploadLoading = true; let params = { file: data, type: "avatar" } vue.$api.home.avatarImage(params, "post").then((res) => { if(res.code == 0){ vue.form.avatar_path = res.data.full_path; vue.form.avatar = res.data.image_name; vue.uploadLoading = false; vue.dialogCropper = false; }else{ vue.$message({type: 'error', message: res.message}); } }); } }) }, // 取消上传 cancelUpload() { let f = document.getElementById('uploads'); if(f.value){ try{ f.value = ''; //for IE11, latest Chrome/Firefox/Opera... }catch(err){ } if(f.value){ //for IE5 ~ IE10 var form = document.createElement('form'), ref = f.nextSibling, p = f.parentNode; form.appendChild(f); form.reset(); p.insertBefore(f,ref); } } }, realTime(data){//预览图片 let vue = this; vue.previews = data;//传给要展示的 }, }, mounted() { let vue = this; vue.user = JSON.parse(localStorage.getItem("lsp_user")) if(vue.user){ vue.getUserInfo() }else{ vue.$message({type: 'warning', message: '未查询到登录信息,请重新登录'}); } } } </script>

css样式

<style lang="scss" scoped> .input-dialog-form{ width: 600px; margin-left: 5%; } .save-form-button{ width:520px; display: inline-block; margin-left: 134px; margin-top: 20px; padding:15px; text-align: center; } /*头像上传*/ .avatar-uploader{ height: 120px; } .avatar-uploader-icon { border: 1px dashed #c0ccda; background-color: #fbfdff; border-radius: 6px; cursor: pointer; width: 120px; height: 120px; text-align: center; position: relative; overflow: hidden; } .upload-icon{ width:50px; height:50px; display: inline-block; margin-top: 30px; } .avatar-uploader-icon:hover { border-color: #409eff; } .avatar { width: 120px; height: 120px; display: block; border-radius: 6px; border: 1px solid #C9D9F5; } .show-preview{ display: inline-block; border: 1px solid #C9D9F5; } .preview-style_1{ transform: scale(0.6667); position: relative; top:30px; border: 2px solid #C9D9F5; } .preview-style_2{ transform: scale(0.3334); position: relative; top:60px; left:-60px; border: 3px solid #C9D9F5; } </style>
最新回复(0)