You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>
<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>

关键修改说明

  1. 新增本地状态控制过渡:在Modal组件内部定义showModal本地响应式状态,用来控制过渡动画的显示/隐藏,不再直接依赖父组件传入的show props
  2. 延迟触发卸载事件:关闭模态框时,先修改本地状态触发淡出动画,等待动画完成(时长和CSS过渡保持一致的500ms)后,再向父组件emitclose事件,让父组件通过v-if卸载组件
  3. 初始化状态同步:根据父组件传入的show props初始化本地状态,保证打开模态框时的正常渲染

内容的提问来源于stack exchange,提问作者dbzx10299

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 06:05:35