先看效果图,这款插件挺有意思的,下面开始详细梳理一下过程
当鼠标经过头像的时候会出现个加号,我们先把外层的需求处理好,然后再处理弹窗打开修改图片的部分 父页面
<a-col :md="24" :lg="8" :style="{ minHeight: '180px' }">
<div class="ant-upload-preview" @click="$refs.modal.edit(1)">
<a-icon type="cloud-upload-o" class="upload-icon" />
<div class="mask">//过渡效果看对应的样式
<a-icon type="plus" />
</div>
<img :src="userAvatar" />
</div>
</a-col>
<avatar-modal ref="modal" @ok="setavatar" />
import { mapState } from 'vuex'//头像保存在vuex中
import AvatarModal from './modules/AvatarModal'
components: {
AvatarModal
},
data(){
return{
userAvatar: '',
}}
computed: {
...mapState({
avatar: state => state.user.avatar,
userInfo: state => state.user.info
}),
created() {
this.userAvatar = this.avatar//页面刚渲染的时候,取vuex中保存过的头像
},
//子组件向父组件传值
setavatar(url) {
console.log(url) //打印结果见下图 ,当子组件点击保存的时候,子组件向父组件传值
this.userAvatar = url
//获取用户头像
if (this.userInfo.avatar) {
this.$store.dispatch('GetAvatar', this.userInfo.avatar)
}
}
.ant-upload-preview {
position: relative;
margin: 0 auto;
width: 100%;
max-width: 180px;
border-radius: 50%;
box-shadow: 0 0 4px
.upload-icon {
position: absolute;
top: 0;
right: 10px;
font-size: 1.4rem;
padding: 0.5rem;
background: rgba(222, 221, 221, 0.7);
border-radius: 50%;
border: 1px solid rgba(0, 0, 0, 0.2);
}
.mask {
opacity: 0;
position: absolute;
background: rgba(0, 0, 0, 0.4);
cursor: pointer;
transition: opacity 0.4s;//规定设置过渡效果的 CSS 属性的名称,规定完成过渡效果需要多少秒或毫秒
&:hover {
opacity: 1;
}
i {
font-size: 2rem;
position: absolute;
top: 50%;
left: 50%;
margin-left: -1rem;
margin-top: -1rem;
color:
}
}
img,
.mask {
width: 100%;
max-width: 180px;
height: 100%;
border-radius: 50%;
overflow: hidden;
}
}
vuex存储头像部分对应代码: 新建a.js 引入封装好的接口
import { viewPic } from '@/api/common'
state中定义数据
avatar: '/avatar.svg',
mutations定义操作数据
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
actions处理异步
//获取用户头像
GetAvatar({ commit }, avatar) {
viewPic(avatar)
.then(res => {
if (res.byteLength > 0) {
commit(
'SET_AVATAR',
'data:image/png;base64,' +
btoa(new Uint8Array(res).reduce((res, byte) => res + String.fromCharCode(byte), ''))
)
} else {
commit('SET_AVATAR', '/avatar.svg')
}
})
.catch(err => {
commit('SET_AVATAR', '/avatar.svg')
})
},
断----------------------------------------------------------------------------------------------------点--------------------------------------------------------------------------- 子页面 首先要安装插件
npm install vue-cropper --save
在页面中引入
import { VueCropper } from 'vue-cropper'
<template>
<a-modal
title="修改头像"
:visible="visible"
:maskClosable="false"
:confirmLoading="confirmLoading"
:width="800"
:footer="null"
@cancel="cancelHandel"
>
<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"
:headers="headers"
:beforeUpload="beforeUpload"
:showUploadList="false"
>
<a-button icon="upload">选择图片</a-button>
</a-upload>
</a-col>
<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>
<a-col :lg="{span: 2, offset: 6}" :md="2">
<a-button type="primary" @click="finish('blob')">保存</a-button>
</a-col>
</a-row>
</a-modal>
</template>
import { VueCropper } from 'vue-cropper'
import { updateAvatar } from '@/api/user'
export default {
components: {
VueCropper,
},
data() {
return {
visible: false,
id: null,
confirmLoading: false,
fileList: [],
uploading: false,
options: {
img: '',
autoCrop: true,
autoCropWidth: 200,
autoCropHeight: 200,
fixedBox: true,
},
previews: {},
userId: this.$store.state.user.userId,
token: this.$store.state.token,
}
},
methods: {
edit(id) {
this.visible = true
this.id = id
/* 获取原始头像 */
},
close() {
this.id = null
this.visible = false
},
cancelHandel() {
this.close()
},
changeScale(num) {
num = num || 1
this.$refs.cropper.changeScale(num)
},
rotateLeft() {
this.$refs.cropper.rotateLeft()
},
rotateRight() {
this.$refs.cropper.rotateRight()
},
beforeUpload(file) {
const reader = new FileReader()
// 把Array Buffer转化为blob 如果是base64不需要
// 转化为base64
reader.readAsDataURL(file)
reader.onload = () => {
this.options.img = reader.result
}
// 转化为blob
// reader.readAsArrayBuffer(file)
return false
},
// 上传图片(点击上传按钮)
finish(type) {
const _this = this
const formData = new FormData()
// 输出
if (type === 'blob') {
this.$refs.cropper.getCropBlob((data) => {
const img = window.URL.createObjectURL(data)
this.model = true
this.modelSrc = img
formData.append('userId', this.userId)
formData.append('headImg', data, 'avatar')
updateAvatar(formData).then((response) => {
if (response && response.code == 0) {
_this.$message.success('上传成功')
_this.$emit('ok', img)
_this.visible = false
}
})
})
} else {
this.$refs.cropper.getCropData((data) => {
this.model = true
this.modelSrc = data
})
}
},
okHandel() {
const vm = this
vm.confirmLoading = true
setTimeout(() => {
vm.confirmLoading = false
vm.close()
vm.$message.success('上传头像成功')
}, 2000)
},
realTime(data) {
this.previews = data
},
},
}
|