在我们的项目中,往往会遇到要将图片进行裁剪/或者缩放后在进行上传使用,最近做了一个修改头像的功能,需要缩放,裁剪等功能。
点击修改头像
修改头像:组件: Ant Design Ant Design Vue (upload 官方文档)
功能需求:1点击头像,显示修改头像的弹框,回显当前头像图片。2.可剪裁图片/放大或者缩小/旋转等。3.点击确定,头像上传成功,回显修改后的头像。
具体思路:1.上传之前,校验图片的格式和大小,点击保存的时候。处理数据,调用接口,回显图 片。2.剪裁和旋转缩放,采用的是vue-cropper 插件 官网: https://gitee.com/yxl-qwe/vue-cropper
上代码
父组件
<avatar-modal ref="modal" @ok="setavatar" v-if="visible" :visible="visible" @cancelAvatar="cancelAvatar" :imgs="img" @okFinish="okFinish" />
<script> import AvatarModal from '../settings/AvatarModal.vue' import { updateAvatar, uploadImg } from '@/api/login' import { mapActions } from 'vuex' data() { return { visible: false, id: null, img:'', } methods: { ...mapActions({ getInfo: 'GetInfo' }), //修改头像 handelAvatar(id) { this.visible = true this.id = id }, cancelAvatar() { console.log('关闭'); this.visible = false this.id = null }, okFinish(type, f) { // 上传图片(点击上传按钮) // const _this = this let file = f const formData = new FormData() // 输出 if (f) { this.$refs.modal.$refs.cropper.getCropBlob((data) => { const time = new Date().getTime(); const fileName = time + "_" + file.name; // blob转file let trueFile = new window.File([data], fileName, { type: data.type, }); formData.append('file', trueFile) uploadImg(formData).then(res => { if (res.code === 2000) { this.visible = false this.img = res.data.url const avatar = { avatar: res.data.url } updateAvatar(avatar).then(res => { if (res.code === 2000) { //提示用户更新成功 this.$message.info(res.message) this.getInfo() this.img='' } }) } }) }) }else{ this.visible = false // this.img='' } }, } </script>
子组件
<template> <a-modal title="修改头像" :visible="visible" :confirmLoading="confirmLoading" :width="800" :maskClosable="false" @cancel="() => { $emit('cancelAvatar') }" @ok="() => { $emit('okFinish', 'blob',file) }"> <a-form :preserve='false'> <a-row> <a-col :xs="24" :md="12" :style="{ height: '350px' }"> <vue-cropper ref="cropper" :img="options.img" :info="true" :autoCrop="options.autoCrop" :autoCropWidth="options.autoCropWidth" :autoCropHeight="options.autoCropHeight" :fixedBox="options.fixedBox" @realTime="realTime"> </vue-cropper> </a-col> <a-col :xs="24" :md="12" :style="{ height: '350px' }"> <div class="avatar-upload-preview"> <img :src="previews.url" :style="previews.img" /> </div> </a-col> </a-row> <br> <a-row> <a-col :lg="2" :md="2"> <a-upload name="file" :beforeUpload="beforeUpload" :showUploadList="false"> <a-button icon="upload">选择图片</a-button> </a-upload> </a-col> <span> <a-col :lg="{ span: 1, offset: 2 }" :md="2"> <a-button icon="plus" @click="changeScale(1)" /> </a-col> <a-col :lg="{ span: 1, offset: 1 }" :md="2"> <a-button icon="minus" @click="changeScale(-1)" /> </a-col> <a-col :lg="{ span: 1, offset: 1 }" :md="2"> <a-button icon="undo" @click="rotateLeft" /> </a-col> <a-col :lg="{ span: 1, offset: 1 }" :md="2"> <a-button icon="redo" @click="rotateRight" /> </a-col> </span> </a-row> </a-form> </a-modal> </template>
<script> export default { props: { visible: { type: Boolean, default:false, }, imgs:{ type:String, default:'' } }, data() { return { file: null, id: null, confirmLoading: false, uploading: false, options: { img: this.imgs, autoCrop: true, autoCropWidth: 200, autoCropHeight: 200, fixedBox: true }, previews: { url: this.$store.getters.userInfo.avatar, }, isFirst:true, isShow:false, } }, methods: { changeScale(num) { if(this.options.img ==''){ return } num = num || 1 this.$refs.cropper.changeScale(num) }, rotateLeft() { if(this.options.img ==''){ return } this.$refs.cropper.rotateLeft() }, rotateRight() { if(this.options.img ==''){ return } this.$refs.cropper.rotateRight() }, beforeUpload(file) { const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/jpg" || file.type === "image/png"; if (!isJpgOrPng) { this.$message.error(`只能上传jpeg/jpg/png格式的图片`); return } const isLt2M = file.size / 1024 / 1024 < 2; if (!isLt2M) { this.$message.error("图片不得大于2MB!"); return } const reader = new FileReader() // 把Array Buffer转化为blob 如果是base64不需要 // 转化为base64 reader.readAsDataURL(file) reader.onload = () => { this.options.img = reader.result } this.file = file return false; }, okHandel() { const vm = this vm.confirmLoading = true setTimeout(() => { vm.confirmLoading = false vm.close() vm.$message.success('上传头像成功') }, 2000) }, realTime(data) { if(this.isFirst){ this.isFirst =false return } this.previews = data }, } } </script>
<style lang="less" scoped> .avatar-upload-preview { position: absolute; top: 50%; transform: translate(50%, -50%); width: 200px; height: 200px; border-radius: 50%; box-shadow: 0 0 4px #ccc; overflow: hidden; img { width: 100%; height: 100%; } } </style>
具体就是这样完成的。
写的比较菜,有问题欢迎在评论区提出讨论,谢谢!