qs_xinchun2026_h5/components/ImageGalleryModal.vue

251 lines
5.1 KiB
Vue

<script setup>
import { ref, watch } from 'vue'
// 组件属性
const props = defineProps({
// 是否显示
visible: {
type: Boolean,
default: false
},
// 图片数组
images: {
type: Array,
default: () => []
},
// 当前索引
currentIndex: {
type: Number,
default: 0
},
// 查看模式:'with-title' 或 'without-title'
mode: {
type: String,
default: 'with-title'
}
})
// 组件事件
const emit = defineEmits(['close', 'update:currentIndex'])
// 当前显示的图片索引
const currentImageIndex = ref(props.currentIndex)
// 监听props变化
watch(() => props.currentIndex, (newVal) => {
currentImageIndex.value = newVal
})
watch(() => props.visible, (newVal) => {
if (newVal) {
currentImageIndex.value = props.currentIndex
}
})
// 切换图片
const prevImage = () => {
currentImageIndex.value = (currentImageIndex.value - 1 + props.images.length) % props.images.length
}
const nextImage = () => {
currentImageIndex.value = (currentImageIndex.value + 1) % props.images.length
}
// 关闭弹窗
const closeModal = () => {
emit('close')
}
// 点击遮罩关闭
const handleOverlayClick = () => {
closeModal()
}
</script>
<template>
<div class="gallery-modal" v-if="visible">
<!-- 遮罩层 -->
<div class="modal-overlay" @click="handleOverlayClick"></div>
<!-- 弹窗内容 -->
<div class="modal-content" :class="{ 'without-title': mode === 'without-title' }">
<!-- 图片区域 -->
<div class="gallery-image-wrapper">
<!-- 无标题模式下的导航按钮 -->
<div v-if="mode === 'without-title'" class="nav-btn prev-btn side-btn" @click="prevImage">
<img src="/static/images/btn_prev.png" alt="上一张" class="nav-icon" />
</div>
<img :src="images[currentImageIndex]?.src" :alt="images[currentImageIndex]?.title" class="gallery-image" />
<!-- 无标题模式下的导航按钮 -->
<div v-if="mode === 'without-title'" class="nav-btn next-btn side-btn" @click="nextImage">
<img src="/static/images/btn_next.png" alt="下一张" class="nav-icon" />
</div>
</div>
<!-- 有标题模式下的控制区域 -->
<div v-if="mode === 'with-title'" class="gallery-controls">
<div class="nav-btn prev-btn" @click="prevImage">
<img src="/static/images/btn_prev.png" alt="上一张" class="nav-icon" />
</div>
<div class="gallery-title">{{ images[currentImageIndex]?.title }}</div>
<div class="nav-btn next-btn" @click="nextImage">
<img src="/static/images/btn_next.png" alt="下一张" class="nav-icon" />
</div>
</div>
</div>
<!-- 关闭按钮(在对话框外边下方) -->
<div class="close-btn" @click="closeModal">
<img src="/static/images/btn_close.png" alt="关闭" class="close-icon" />
</div>
</div>
</template>
<style scoped>
/* 弹窗容器 */
.gallery-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 1000;
}
/* 遮罩层 */
.modal-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
}
/* 弹窗内容 */
.modal-content {
position: relative;
width: 700rpx;
background-color: #d72717;
border-radius: 20rpx;
padding: 30rpx;
box-sizing: border-box;
z-index: 1001;
animation: modalIn 0.3s ease;
}
/* 无标题模式下的弹窗内容 */
.modal-content.without-title {
padding-bottom: 30rpx;
}
/* 图片区域 */
.gallery-image-wrapper {
position: relative;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
/* 无标题模式下的侧边导航按钮 */
.side-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 10;
}
.side-btn.prev-btn {
left: -40rpx;
}
.side-btn.next-btn {
right: -40rpx;
}
@keyframes modalIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* 关闭按钮(在对话框外边下方) */
.close-btn {
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 1001;
margin-top: 30rpx;
}
.close-icon {
width: 100%;
height: 100%;
object-fit: contain;
}
/* 上方图片区域 */
.gallery-image-wrapper {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20rpx;
}
.gallery-image {
width: 100%;
height: auto;
max-height: 600rpx;
object-fit: contain;
border-radius: 20rpx;
display: block;
}
/* 下方控制区域 */
.gallery-controls {
display: flex;
align-items: center;
justify-content: space-between;
height: 80rpx;
}
.nav-btn {
width: 70rpx;
height: 70rpx;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
flex-shrink: 0;
}
.nav-icon {
width: 100%;
height: 100%;
object-fit: contain;
}
.gallery-title {
flex: 1;
text-align: center;
color: #fff;
font-size: 40rpx;
font-weight: 500;
letter-spacing: 6rpx;
padding: 0 20rpx;
}
</style>