dma_handbook/docs/.vuepress/components/longPic.vue
2026-03-12 14:43:05 +08:00

191 lines
4.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import { ref, onMounted, watch, onUnmounted, getCurrentInstance } from 'vue'
const props = defineProps({
src: {
type: String,
required: true
},
alt: {
type: String,
default: '图片'
},
maxHeight: {
type: Number,
default: 500
}
})
const isExpanded = ref(false)
const showExpand = ref(false)
const isImageLoaded = ref(false)
const imgRef = ref(null)
const resizeObserver = ref(null)
const instance = getCurrentInstance()
// 全局通知图片加载/尺寸变化
const notifyImageLoaded = () => {
if (instance?.appContext.config.globalProperties.$notifyImageLoaded) {
instance.appContext.config.globalProperties.$notifyImageLoaded();
}
document.dispatchEvent(new CustomEvent('longPicImageLoaded'));
};
// 检查图片高度并通知外部
const checkImageHeight = (img) => {
if (typeof window === 'undefined') return
const naturalHeight = img.naturalHeight || img.offsetHeight
console.log(props.alt, naturalHeight, '图片实际高度')
// 仅初始化时判断是否显示展开按钮
showExpand.value = naturalHeight > props.maxHeight
isImageLoaded.value = true
notifyImageLoaded()
}
// 图片加载完成处理
const handleImageLoad = (event) => {
if (isImageLoaded.value) return
checkImageHeight(event.target)
}
// 监听元素尺寸变化
const observeResize = () => {
if (typeof window === 'undefined' || !window.ResizeObserver) return
resizeObserver.value = new ResizeObserver((entries) => {
notifyImageLoaded()
})
if (imgRef.value) {
resizeObserver.value.observe(imgRef.value)
}
}
// 展开/收起切换
const toggleExpand = () => {
isExpanded.value = !isExpanded.value
setTimeout(() => notifyImageLoaded(), 100)
}
// 生命周期
onMounted(() => {
if (typeof window === 'undefined') return
const img = imgRef.value
if (img && img.complete) {
checkImageHeight(img)
}
observeResize()
})
onUnmounted(() => {
if (resizeObserver.value) {
resizeObserver.value.disconnect()
}
})
</script>
<template>
<div class="image-container">
<div
class="image-wrapper"
:class="{ 'expanded': isExpanded }"
:style="{
maxHeight: !isExpanded ? `${maxHeight}px` : 'none',
aspectRatio: !isExpanded ? '16/9' : 'unset' // 展开后取消宽高比限制
}"
>
<img
ref="imgRef"
:src="src"
:alt="alt"
@load="handleImageLoad"
class="responsive-image"
loading="eager"
decoding="async"
>
</div>
<!-- 按钮组容器 -->
<div v-if="showExpand" class="hint-wrapper">
<div class="expand-hint" @click="toggleExpand" v-show="!isExpanded">
<span>点击查看完整图片</span>
</div>
<div class="collapse-hint" @click="toggleExpand" v-show="isExpanded">
<span>收起图片</span>
</div>
</div>
</div>
</template>
<style scoped>
.image-container {
position: relative;
width: 100%;
margin: 0 auto;
min-height: 100px; /* 兜底高度,防止加载前塌陷 */
}
.image-wrapper {
width: 100%;
overflow: hidden;
transition: max-height 0.3s ease-in-out;
position: relative;
/* 移除固定aspect-ratio改为动态绑定 */
}
/* 未展开时添加渐变遮罩 */
.image-wrapper:not(.expanded)::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 80px;
background: linear-gradient(transparent, rgba(255,255,255,0.95));
pointer-events: none;
}
/* 展开后隐藏遮罩 */
.image-wrapper.expanded::after {
display: none;
}
.responsive-image {
width: 100%;
height: auto;
display: block;
object-fit: contain; /* 确保图片完整显示,不拉伸 */
}
/* 按钮容器 */
.hint-wrapper {
width: 100%;
}
.expand-hint, .collapse-hint {
text-align: center;
padding: 8px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
margin-top: 8px;
transition: background-color 0.3s;
}
.expand-hint {
background: rgba(64, 158, 255, 0.1);
color: #409eff;
}
.expand-hint:hover {
background: rgba(64, 158, 255, 0.2);
}
.collapse-hint {
background: rgba(103, 194, 58, 0.1);
color: #67c23a;
}
.collapse-hint:hover {
background: rgba(103, 194, 58, 0.2);
}
</style>