<template>
<div class="corpping-warp">
<!-- 显示头像-选择图片 -->
<el-upload action :on-change="selectImage" :show-file-list="false" accept=".jpg,.png" :auto-upload="false">
<div class="avatar-warp">
<el-avatar :size="110" :src="avatarUrl"></el-avatar>
<span class="el-icon-edit"></span>
</div>
</el-upload>
<el-dialog
title="更换头像"
v-model="dialogVisible"
width="40%"
>
<!-- 图片裁剪 -->
<Cropper ref="cropper" stencil-component="circle-stencil" class="cropper" :src="img" :debounce="false" @change="onChange"/>
<!-- 预览图 -->
<Preview class="cropper-preview" :image="result.image" :coordinates="result.coordinates"/>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<DlButton label="确 定" @click="crop"></DlButton>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import DlButton from ‘@/components/common/DlButton‘
import { ref, toRefs, watch } from ‘vue‘
import { cos, cosUpload } from ‘@/utils/cosUpload‘
export default {
components: { DlButton },
props: {
defaultAvatarUrl: {
type: String,
default: ‘‘
}
},
setup (props) {
const { defaultAvatarUrl } = toRefs(props)
const avatarUrl = ref(‘‘)
watch(defaultAvatarUrl, (value, oldValue) => {
avatarUrl.value = defaultAvatarUrl.value
})
return {
avatarUrl
}
},
data: function () {
return {
dialogVisible: false, // 对话框显示
img: ‘‘, // 头像地址
change: {
coordinates: {}, // on-change的坐标
image: null // on-change预览图
},
result: { // 确定的裁剪图
coordinates: {},
image: null
},
imageFile: null, // 原始文件
avatarFile: { // 头像文件
file_path: null,
origin_file_name: null,
file_mime_type: null,
file_extension: null,
file_size: null
}
}
},
methods: {
// 选择裁剪图片
selectImage (file) {
console.log(‘选择的文件信息‘, file)
this.imageFile = file.raw
const preUrl = URL.createObjectURL(file.raw)
this.img = preUrl
this.dialogVisible = true
},
/* 确认截取部位 */
crop () {
const { canvas } = this.$refs.cropper.getResult()
// 预览路径
this.avatarUrl = canvas.toDataURL()
// Blob对象
canvas.toBlob(item => {
item.name = this.imageFile.name
cosUpload(item, cos, ‘/test/‘).then((res) => {
this.avatarFile.file_path = res
this.avatarFile.origin_file_name = this.imageFile.name
this.avatarFile.file_mime_type = item.type
this.avatarFile.file_extension = this.imageFile.name.split(‘.‘).pop().toLowerCase()
this.avatarFile.file_size = item.size
this.$emit(‘sendAvatar‘, this.avatarFile)
})
}, ‘image/jpeg‘, 0.8)
// console.log(‘结果路径‘, this.avatarUrl)
this.dialogVisible = false
},
onChange ({ coordinates, image }) {
this.result.coordinates = coordinates
this.result.image = image
}
},
emits: [‘sendAvatar‘]
}
</script>
<style lang="scss" scoped>
.cropper {
height: 500px;
background: #DDD;
}
.corpping-warp :deep(.el-dialog){
margin-top: 5vh !important;
}
.avatar-warp{
width: 110px;
height: 110px;
overflow:hidden;
border-radius: 50%;
position: relative;
display: flex;
justify-content: center;
align-items: center;
span {
position: absolute;
top: 50%;
left: 50%;
color: #fff;
transform: translate(-50%, -50%);
font-size: 30px;
cursor: pointer;
}
.el-icon-edit{
opacity: 0;
transition: all 0.3s;
}
&:hover{
.el-icon-edit{
opacity: 1;
}
}
}
.cropper-preview{
width: 110px;
height: 110px;
overflow: hidden;
margin: 20px auto;
border-radius: 50%;
}
</style>
vue-advanced-cropper和腾讯云对象存储封装的头像上传组件