feat: 增加HoverImagePreview组件

This commit is contained in:
renxiaodong
2025-08-11 22:40:54 +08:00
parent 6eb302b0ae
commit 8cda6cae64
3 changed files with 142 additions and 5 deletions

View File

@ -0,0 +1,93 @@
<!--
* @Author: RenXiaoDong
* @Date: 2025-08-11 22:15:35
-->
<template>
<a-popover
:trigger="'hover'"
class="hover-big-image-preview-popover"
:position="props.position"
:mouse-enter-delay="props.enterDelay"
:mouse-leave-delay="props.leaveDelay"
:disabled="!props.src"
>
<template #content>
<div class="preview-container" :style="containerStyle">
<img :src="props.src" alt="preview" class="preview-image" />
</div>
</template>
<slot />
</a-popover>
</template>
<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue';
import type { ImageOrientation } from '@/utils/tools';
import { getImageOrientationByUrl } from '@/utils/tools';
interface Props {
src: string;
position?: 'top' | 'tl' | 'tr' | 'bottom' | 'bl' | 'br' | 'left' | 'lt' | 'lb' | 'right' | 'rt' | 'rb';
enterDelay?: number;
leaveDelay?: number;
}
const props = withDefaults(defineProps<Props>(), {
position: 'right',
enterDelay: 100,
leaveDelay: 200,
});
const orientation = ref<ImageOrientation>('landscape');
const resolveOrientation = async () => {
if (!props.src) {
orientation.value = 'landscape';
return;
}
const o = await getImageOrientationByUrl(props.src);
orientation.value = o === 'square' ? 'landscape' : o;
};
onMounted(resolveOrientation);
watch(() => props.src, resolveOrientation);
const containerStyle = computed(() => {
// 竖图: 306x400横图: 400x251
const isPortrait = orientation.value === 'portrait';
const width = isPortrait ? 306 : 400;
const height = isPortrait ? 400 : 251;
return {
width: `${width}px`,
height: `${height}px`,
} as Record<string, string>;
});
</script>
<style lang="scss">
.hover-big-image-preview-popover {
.arco-popover-popup-content {
padding: 16px !important;
border-radius: 8px;
background: #fff;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1);
}
.preview-container {
box-sizing: border-box;
border-radius: 8px;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.preview-image {
width: 100%;
height: 100%;
object-fit: contain;
}
}
</style>