快速使用
结合 el-dialog 函数式调用
vue
<script setup lang="ts">
import { isCancelError, getErrorMessage } from 'vue-select-avatar'
import { ElMessage } from 'element-plus'
import { selectAvatar } from './index'
import { ref } from 'vue'
const src = ref('')
const fileSize = ref(0)
const size = ref(0)
const handleSelect = async () => {
try {
const file = await selectAvatar()
if (src.value) {
URL.revokeObjectURL(src.value)
}
src.value = URL.createObjectURL(file)
fileSize.value = file.size
} catch (error) {
// 错误处理
if (isCancelError(error)) return
console.error(error)
ElMessage.error(getErrorMessage(error))
}
}
const handleClear = () => {
src.value = ''
}
const handleLoad = (e: Event) => {
size.value = (e.target as HTMLImageElement).naturalWidth
}
// 辅助函数
const formatBytes = (bytes: number, decimals = 2) => {
const k = 1024
const dm = decimals < 0 ? 0 : decimals
const units = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + units[i] + 'B'
}
</script>
<template>
<button @click="handleSelect" class="select-avatar-button">选择头像</button>
<template v-if="src">
<div style="font-size: 13px">{{ `${size}x${size} ${formatBytes(fileSize)}` }}</div>
<img :src="src" @load="handleLoad" />
<button @click="handleClear">清除</button>
</template>
</template>
<style scoped>
button {
all: revert;
}
</style>ts
import { selectImage, SelectAvatarError } from 'vue-select-avatar'
import Content from './content.vue'
import { createVNode, render } from 'vue'
export const selectAvatar = async () => {
const res = await selectImage({
maxFileSize: 20 * 1024 * 1024,
// 其他配置...
})
return new Promise<File>((resolve, reject) => {
let isConfirm = false
let file: File | undefined
let error: Error | undefined
const el = document.createElement('div')
const vnode = createVNode(Content, {
info: res,
onConfirm: (_file: File) => {
file = _file
isConfirm = true
},
onClose: () => {
render(null, el)
el.remove()
if (isConfirm) {
resolve(file!)
} else {
reject(error || new SelectAvatarError('CANCEL'))
}
},
onError(err: Error) {
error = err
},
})
render(vnode, el)
document.body.appendChild(el)
})
}vue
<script setup lang="ts">
import 'vue-select-avatar/style.css'
import { Viewport, type ImageInfo } from 'vue-select-avatar'
import { ElDialog, ElButton } from 'element-plus'
import { ref, watchEffect } from 'vue'
interface Props {
info: ImageInfo
}
defineProps<Props>()
const viewportRef = ref<InstanceType<typeof Viewport>>()
const visible = ref(true)
const emit = defineEmits(['close', 'confirm', 'error'])
const handleCancel = () => {
visible.value = false
}
const handleConfirm = async () => {
try {
const file = await viewportRef.value?.cropper<File>({
// 裁剪配置...
})
emit('confirm', file)
visible.value = false
} catch (error) {
emit('error', error)
visible.value = false
}
}
watchEffect(() => {
if (!visible.value) {
emit('close')
}
})
</script>
<template>
<el-dialog v-model="visible" title="选择图片" width="332" append-to-body>
<Viewport grid :info="info" ref="viewportRef" />
<template #footer>
<div class="dialog-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</div>
</template>
</el-dialog>
</template>