208 lines
4.0 KiB
Vue
208 lines
4.0 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
|
||
}
|
||
})
|
||
|
||
// 组件事件
|
||
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">
|
||
<!-- 图片区域 -->
|
||
<div class="gallery-image-wrapper">
|
||
<img :src="images[currentImageIndex]?.src" :alt="images[currentImageIndex]?.title" class="gallery-image" />
|
||
</div>
|
||
|
||
<!-- 控制区域 -->
|
||
<div 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;
|
||
}
|
||
|
||
@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> |