mirror of
https://gitee.com/lijingbo-2021/open-anylink-web.git
synced 2025-12-30 11:02:25 +00:00
使用vue-cropper作头像编辑工具
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
"protobufjs": "^7.4.0",
|
||||
"uuid": "^10.0.0",
|
||||
"vue": "^3.4.29",
|
||||
"vue-cropper": "^1.1.1",
|
||||
"vue-router": "^4.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -38,6 +38,9 @@ importers:
|
||||
vue:
|
||||
specifier: ^3.4.29
|
||||
version: 3.4.38
|
||||
vue-cropper:
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
vue-router:
|
||||
specifier: ^4.3.3
|
||||
version: 4.4.3(vue@3.4.38)
|
||||
@@ -1603,6 +1606,9 @@ packages:
|
||||
terser:
|
||||
optional: true
|
||||
|
||||
vue-cropper@1.1.1:
|
||||
resolution: {integrity: sha512-WsqKMpaBf9Osi1LQlE/5AKdD0nHWOy1asLXocaG8NomOWO07jiZi968+/PbMmnD0QbPJOumDQaGuGa13qys85A==}
|
||||
|
||||
vue-demi@0.14.10:
|
||||
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -3145,6 +3151,8 @@ snapshots:
|
||||
fsevents: 2.3.3
|
||||
sass: 1.77.8
|
||||
|
||||
vue-cropper@1.1.1: {}
|
||||
|
||||
vue-demi@0.14.10(vue@3.4.38):
|
||||
dependencies:
|
||||
vue: 3.4.38
|
||||
|
||||
@@ -2,57 +2,74 @@
|
||||
import { ref } from 'vue'
|
||||
import { userStore } from '@/stores'
|
||||
import { Plus, Upload } from '@element-plus/icons-vue'
|
||||
import selectAvatar from '@/assets/select_avatar.jpg'
|
||||
import { userUploadAvatarService } from '@/api/user'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import 'vue-cropper/dist/index.css'
|
||||
import { VueCropper } from 'vue-cropper'
|
||||
|
||||
defineProps(['modelValue'])
|
||||
const emit = defineEmits(['update:modelValue', 'update:newAvatar'])
|
||||
const userData = userStore()
|
||||
|
||||
const uploadRef = ref()
|
||||
const imgUrl = ref(userData.user.avatar)
|
||||
const cropper = ref()
|
||||
const img = ref('')
|
||||
const previewImg = ref('')
|
||||
const isLoading = ref(false)
|
||||
let selectedFile
|
||||
|
||||
const onSelected = (file) => {
|
||||
imgUrl.value = URL.createObjectURL(file.raw)
|
||||
selectedFile = file.raw
|
||||
}
|
||||
|
||||
const onSuccess = () => {}
|
||||
|
||||
const beforeUpload = () => {}
|
||||
|
||||
const onUpload = async () => {
|
||||
if (!selectedFile) {
|
||||
ElMessage.warning('您还未选择新头像!')
|
||||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
try {
|
||||
const res = await userUploadAvatarService({ file: selectedFile })
|
||||
emit('update:newAvatar', res.data.data)
|
||||
emit('update:modelValue', false)
|
||||
selectedFile = null
|
||||
ElMessage.success('头像上传成功')
|
||||
} catch (error) {
|
||||
/* empty */
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
const fileName = ref('')
|
||||
|
||||
// 打开的时候触发
|
||||
const onOpen = () => {
|
||||
imgUrl.value = userData.user.avatar
|
||||
fileName.value = userData.user.avatar?.split('/').pop()
|
||||
img.value = userData.user.avatar
|
||||
previewImg.value = img.value
|
||||
}
|
||||
|
||||
// 关闭的时候触发
|
||||
const onClose = () => {
|
||||
isLoading.value = false
|
||||
}
|
||||
|
||||
// 选择了文件触发
|
||||
const onSelected = (file) => {
|
||||
fileName.value = file.name
|
||||
img.value = URL.createObjectURL(file.raw)
|
||||
previewImg.value = img.value
|
||||
}
|
||||
|
||||
const onUpload = async () => {
|
||||
cropper.value.getCropBlob(async (blob) => {
|
||||
const lastDotIndex = fileName.value.lastIndexOf('.')
|
||||
const prefix = fileName.value.substring(0, lastDotIndex)
|
||||
const suffix = fileName.value.substring(lastDotIndex)
|
||||
let file = new File(
|
||||
[blob],
|
||||
`${prefix}_${cropper.value.cropW}x${cropper.value.cropH}${suffix}`,
|
||||
{
|
||||
type: blob.type,
|
||||
lastModified: Date.now()
|
||||
}
|
||||
)
|
||||
|
||||
isLoading.value = true
|
||||
try {
|
||||
const res = await userUploadAvatarService({ file: file })
|
||||
emit('update:newAvatar', res.data.data)
|
||||
emit('update:modelValue', false)
|
||||
ElMessage.success('头像上传成功')
|
||||
} catch (error) {
|
||||
/* empty */
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const stopCrop = () => {
|
||||
cropper.value.getCropData((data) => {
|
||||
previewImg.value = data
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -72,10 +89,21 @@ const onClose = () => {
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:on-change="onSelected"
|
||||
:on-success="onSuccess"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<img :src="imgUrl || selectAvatar" class="avatar" />
|
||||
<div class="canvas" @click.stop style="width: 400px; height: 400px">
|
||||
<vueCropper
|
||||
ref="cropper"
|
||||
class="avatar"
|
||||
:img="img"
|
||||
:full="true"
|
||||
:autoCrop="true"
|
||||
:autoCropWidth="250"
|
||||
:autoCropHeight="250"
|
||||
:canScale="true"
|
||||
:centerBox="true"
|
||||
@mouseup="stopCrop"
|
||||
></vueCropper>
|
||||
</div>
|
||||
</el-upload>
|
||||
</div>
|
||||
|
||||
@@ -83,9 +111,9 @@ const onClose = () => {
|
||||
<div class="preview-area">
|
||||
<span style="font-size: 16px">预览</span>
|
||||
|
||||
<el-avatar class="preview-100" :src="imgUrl || selectAvatar" />
|
||||
<el-avatar class="preview-100" :src="previewImg" />
|
||||
<span>100×100</span>
|
||||
<el-avatar class="preview-40" :src="imgUrl || selectAvatar" />
|
||||
<el-avatar class="preview-40" :src="previewImg" />
|
||||
<span>40×40</span>
|
||||
</div>
|
||||
<div class="button-area">
|
||||
@@ -151,12 +179,4 @@ const onClose = () => {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
object-fit: cover;
|
||||
text-align: center;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user