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

232 lines
5.5 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
2026-03-26 17:08:01 +08:00
},
// 新增:外部可配置宽度(支持数字/字符串,如 300 | '300px' | '100%'
width: {
type: [Number, String],
default: '100%'
2025-09-29 16:51:36 +08:00
}
})
const isExpanded = ref(false)
2026-03-26 17:08:01 +08:00
const showExpand = ref(false) // 仅当高度超maxHeight时显示展开/收起按钮
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-26 17:08:01 +08:00
// 检查图片高度并控制展开按钮显示
// 核心修改未超过maxHeight时不显示按钮也不处理任何高度限制逻辑
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-03-26 17:08:01 +08:00
2026-02-06 11:17:10 +08:00
const naturalHeight = img.naturalHeight || img.offsetHeight
console.log(props.alt, naturalHeight, '图片实际高度')
2026-03-26 17:08:01 +08:00
// 关键逻辑仅当图片高度超过maxHeight时才显示展开按钮
2026-02-06 11:17:10 +08:00
showExpand.value = naturalHeight > props.maxHeight
isImageLoaded.value = true
2026-03-26 17:08:01 +08:00
// 未超高度时直接展开(取消高度限制)
if (!showExpand.value) {
isExpanded.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
2026-03-26 17:08:01 +08:00
2026-03-12 14:43:05 +08:00
resizeObserver.value = new ResizeObserver((entries) => {
2026-03-26 17:08:01 +08:00
// 尺寸变化时重新检查高度(适配窗口缩放等场景)
const img = imgRef.value
if (img && isImageLoaded.value) {
checkImageHeight(img)
}
2026-03-12 14:43:05 +08:00
notifyImageLoaded()
})
2026-03-26 17:08:01 +08:00
2026-03-12 14:43:05 +08:00
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
2026-03-26 17:08:01 +08:00
// 展开/收起切换仅当showExpand为true时触发
2025-09-29 16:51:36 +08:00
const toggleExpand = () => {
2026-03-26 17:08:01 +08:00
if (!showExpand.value) return // 未超高度时不执行切换逻辑
2025-09-29 16:51:36 +08:00
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-26 17:08:01 +08:00
// 格式化宽度值(处理数字/字符串输入)
const formatWidth = () => {
if (typeof props.width === 'number') {
return `${props.width}px`
}
return props.width
}
2026-03-12 14:43:05 +08:00
// 生命周期
onMounted(() => {
if (typeof window === 'undefined') return
2026-03-26 17:08:01 +08:00
2026-03-12 14:43:05 +08:00
const img = imgRef.value
if (img && img.complete) {
checkImageHeight(img)
}
2026-03-26 17:08:01 +08:00
2026-03-12 14:43:05 +08:00
observeResize()
})
onUnmounted(() => {
if (resizeObserver.value) {
resizeObserver.value.disconnect()
}
2026-02-06 11:17:10 +08:00
})
2026-03-26 17:08:01 +08:00
// 监听width属性变化重新通知尺寸更新
watch(() => props.width, () => {
if (isImageLoaded.value) {
notifyImageLoaded()
}
})
2025-09-29 16:51:36 +08:00
</script>
<template>
2026-03-26 17:08:01 +08:00
<div class="image-container" :style="{ width: formatWidth() }">
<!-- 核心修改未超高度时取消maxHeight和aspectRatio限制 -->
2025-09-29 16:51:36 +08:00
<div
2026-02-06 11:17:10 +08:00
class="image-wrapper"
:class="{ 'expanded': isExpanded }"
2026-03-12 14:43:05 +08:00
:style="{
2026-03-26 17:08:01 +08:00
// 仅当需要限制高度时才设置maxHeight
maxHeight: showExpand && !isExpanded ? `${maxHeight}px` : 'none',
// 仅当需要限制高度时才设置aspectRatio
aspectRatio: showExpand && !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-26 17:08:01 +08:00
<!-- 仅当showExpand为true时显示展开/收起按钮 -->
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;
2026-02-06 11:17:10 +08:00
margin: 0 auto;
2026-03-12 14:43:05 +08:00
min-height: 100px; /* 兜底高度,防止加载前塌陷 */
2026-03-26 17:08:01 +08:00
/* 宽度由外部配置控制 */
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-26 17:08:01 +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>