<template> <Teleport to="body"> <Transition name="fade"> <div v-if="visible" class="guide-modal-overlay" @click.self="handleClose"> <Transition :name="transitionName" mode="out-in" @before-leave="beforeLeave" @after-leave="afterLeave"> <div class="guide-modal" :key="currentIndex"> <!-- 使用插槽或v-html展示内容 --> <div class="guide-content"> <slot :index="currentIndex"> <div v-html="guideList[currentIndex]?.noticeContent"></div> </slot> </div> <div class="guide-footer"> <button class="guide-button" @click="handleAction"> {{ isLastPage ? '我知道了' : '下一页' }} </button> </div> </div> </Transition> </div> </Transition> </Teleport> </template> <script setup lang="ts"> import { ref, computed } from 'vue' interface Props { guideList: string[] modelValue: boolean } const props = defineProps<Props>() const emit = defineEmits(['update:modelValue']) const currentIndex = ref(0) const slideDirection = ref('next') const transitionName = computed(() => `slide-${slideDirection.value}`) const visible = computed({ get: () => props.modelValue, set: (value) => emit('update:modelValue', value) }) const isLastPage = computed(() => currentIndex.value === props.guideList.length - 1) const handleAction = () => { if (isLastPage.value) { handleClose() } else { slideDirection.value = 'next' currentIndex.value++ } } const handleClose = () => { visible.value = false // 重置状态 setTimeout(() => { currentIndex.value = 0 slideDirection.value = 'next' }, 300) } const beforeLeave = () => { document.body.style.overflow = 'hidden' } const afterLeave = () => { document.body.style.overflow = '' } </script> <style lang="scss" scoped> .guide-modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 1000; } .guide-modal { background: #fff; border-radius: 5px; width: 100%; // 调整宽度为90% height: 80vh; // 设置高度为视口高度的70% position: relative; display: flex; flex-direction: column; overflow: hidden; // 防止内容溢出 } .guide-content { flex: 1; overflow-y: auto; // 内容过多时可滚动 padding: 20px; // 允许v-html内容继承样式 :deep(*) { max-width: 100%; height: auto; } } .guide-footer { background: #fff; // 确保底部背景色 border-top: 1px solid #eee; } .guide-button { width: 100%; // 按钮宽度设为90% margin: 0 auto; display: block; background: red; color: #fff; border: none; padding: 12px 0; font-size: 16px; cursor: pointer; transition: opacity 0.3s; } // 淡入淡出动画 .fade-enter-active, .fade-leave-active { transition: opacity 0.3s ease; } .fade-enter-from, .fade-leave-to { opacity: 0; } // 滑动动画 .slide-next-enter-active, .slide-next-leave-active, .slide-prev-enter-active, .slide-prev-leave-active { transition: all 0.3s ease-out; } .slide-next-enter-from { transform: translateX(100%); opacity: 0; } .slide-next-leave-to { transform: translateX(-100%); opacity: 0; } .slide-prev-enter-from { transform: translateX(-100%); opacity: 0; } .slide-prev-leave-to { transform: translateX(100%); opacity: 0; } </style>