Vue中用v-if延迟组件挂载同时保留过渡效果的实现方案
解决Vue模态框v-if卸载导致淡出过渡失效问题
问题背景
我用Vue构建模态框时有两个核心需求:
- 通过
v-if指令延迟Modal组件挂载,避免页面加载时就挂载组件(解决iOS端模态框的常见兼容问题,同时需在组件onMounted钩子中设置body的position: fixed属性及对应top值) - 保留模态框的淡入淡出过渡动画
当前问题:打开模态框时组件正常触发mounted钩子,且通过appear属性实现了淡入效果;但关闭时,父组件的v-if会直接卸载Modal组件,导致淡出过渡动画完全失效。
原始代码
父组件代码
<script setup> const showModal = ref(false) </script> <button @click="showModal = true">show modal</button> <Teleport to=".vue-modal-target"> <Modal :show="showModal" @close="showModal = false" v-if="showModal"> <ContactForm /> </Modal> </Teleport>
Modal.vue代码
<script setup> onMounted(() => { console.log('mounted') }) onUnmounted(() => { console.log('unmounted') }) </script> <template> <Transition appear name="modal"> <div v-if="show" class="modal-wrapper"> <div class="modal-mask"></div> <div class="modal-container"> <button class="close-btn" @click="$emit('close')" style="color: #fff;">X</button> <div class="modal-container__inner"> <slot /> </div> </div> </div> </Transition> </template> <style> .modal-enter-from, .modal-leave-to { opacity: 0; } .modal-enter-to, .modal-leave-from { opacity: 1; } .modal-enter-active, .modal-leave-active { transition: all 0.5s ease-in-out; } </style>
解决方案代码
父组件代码(无变动)
<script setup> const showModal = ref(false) </script> <button @click="showModal = true">show modal</button> <Teleport to=".vue-modal-target"> <Modal :show="showModal" @close="showModal = false" v-if="showModal"> <ContactForm /> </Modal> </Teleport>
修改后的Modal.vue代码
<script setup> onMounted(() => { console.log('mounted') }) onUnmounted(() => { console.log('unmounted') }) const props = defineProps({ show: Boolean }) const showModal = ref(false) if (props.show === true) showModal.value = true const emit = defineEmits(['close']) function handleClose() { showModal.value = false setTimeout(() => { emit('close') }, 500) } </script> <template> <Transition appear name="modal"> <div v-if="showModal" class="modal-wrapper"> <div class="modal-mask"></div> <div class="modal-container"> <button class="close-btn" @click="handleClose" style="color: #fff;">X</button> <div class="modal-container__inner"> <slot /> </div> </div> </div> </Transition> </template> <style> .modal-enter-from, .modal-leave-to { opacity: 0; } .modal-enter-to, .modal-leave-from { opacity: 1; } .modal-enter-active, .modal-leave-active { transition: all 0.5s ease-in-out; } </style>
关键修改说明
- 新增本地状态控制过渡:在Modal组件内部定义
showModal本地响应式状态,用来控制过渡动画的显示/隐藏,不再直接依赖父组件传入的showprops - 延迟触发卸载事件:关闭模态框时,先修改本地状态触发淡出动画,等待动画完成(时长和CSS过渡保持一致的500ms)后,再向父组件emit
close事件,让父组件通过v-if卸载组件 - 初始化状态同步:根据父组件传入的
showprops初始化本地状态,保证打开模态框时的正常渲染
内容的提问来源于stack exchange,提问作者dbzx10299
相关产品推荐
相关产品推荐

