Nuxt 3 路由切换后Modal组件Prop更新异常问题
问题:路由切换返回后,Prop控制的Modal无法再次显示
我开发了一个通过Prop控制显示的Modal组件,组件可触发close事件。正常使用时一切正常,但切换页面路由后返回承载该Modal的页面,即便Vue DevTools显示Prop值已更新,Modal也无法再次显示。
页面中Modal的使用代码
<script setup> const subgroupModal = ref(false); const toggleModal = () => { subgroupModal.value = !subgroupModal.value; }; const closeModal = () => { subgroupModal.value = false; }; </script> <template> <button @click="toggleModal"> <el-icon :size="30"> <el-icon-circle-plus-filled class="relative text-orange top-[1px]" /> </el-icon> </button> <ContentModal @close-modal="closeModal" :modalActive="subgroupModal"> modal content </ContentModal> </template>
Modal组件代码
<script setup> const props = defineProps({ modalActive: { type: Boolean, required: true } }); const emit = defineEmits(['closeModal']); const close = () => { emit('closeModal'); }; </script> <template> <Teleport to="body"> <Transition enter-from-class="opacity-0" leave-to-class="opacity-0" enter-active-class="transition duration-300" leave-active-class="transition duration-300" > <div v-if="modalActive" class="fixed z-50 flex items-start justify-center w-full h-full bg-black bg-opacity-60" > <div class="flex bg-white flex-col absolute top-[10%] md:top-[20%] sm:max-w-[1160px] w-[calc(100%-2.25rem)] pb-8 md:pb-12" > <div class="flex justify-end pt-3 pr-3 mb-3 md:mb-8"> <button type="button" @click="close"> <el-icon :size="55"> <el-icon-close-bold class="text-orange" /> </el-icon> </button> </div> <slot></slot> </div> </div> </Transition> </Teleport> </template>
解决方案
核心原因
问题出在Teleport组件的DOM管理上:路由切换时,承载Modal的页面组件被卸载,但Teleport到body的Modal DOM可能未被正确清理;或者重新挂载后,Transition组件的状态没有重置,导致无法响应modalActive的变化。
方法1:给Teleport添加唯一Key
给Teleport绑定与路由关联的唯一key,确保路由切换后Teleport重新渲染,清理旧DOM并创建新实例:
<!-- 修改Modal组件的Teleport部分 --> <Teleport to="body" :key="$route.fullPath"> <!-- 原Transition和Modal内容 --> </Teleport>
需要在Modal组件中引入路由实例:
<script setup> import { useRoute } from 'vue-router'; const route = useRoute(); // 原props和emit代码 </script>
方法2:用v-show替代v-if(配合Transition的appear属性)
将Modal外层的v-if改为v-show,同时给Transition添加appear属性,确保初始渲染时触发过渡效果:
<Transition appear enter-from-class="opacity-0" leave-to-class="opacity-0" enter-active-class="transition duration-300" leave-active-class="transition duration-300" > <div v-show="modalActive" class="fixed z-50 flex items-start justify-center w-full h-full bg-black bg-opacity-60" > <!-- 原Modal内容 --> </div> </Transition>
v-show仅控制元素显示隐藏,DOM始终存在,避免了v-if卸载DOM导致的Teleport残留问题,路由返回后能正确响应prop变化。
方法3:页面卸载时重置Modal状态
在承载Modal的页面组件中,通过onUnmounted钩子重置控制变量,确保路由返回时状态初始化为false:
<script setup> import { ref, onUnmounted } from 'vue'; const subgroupModal = ref(false); const toggleModal = () => { subgroupModal.value = !subgroupModal.value; }; const closeModal = () => { subgroupModal.value = false; }; onUnmounted(() => { subgroupModal.value = false; }); </script>
该方法可配合前两种方法使用,避免残留状态影响下次页面渲染。
内容的提问来源于stack exchange,提问作者MonTOne
相关产品推荐
相关产品推荐

