dma_handbook/docs/.vuepress/components/longPic.vue

191 lines
4.2 KiB
Vue
Raw Normal View History

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