Nuxt UI中useModal程序化打开多模态框被覆盖问题求助
解决Nuxt UI程序化打开多模态框实例被覆盖的问题
问题描述
我有两个Nuxt UI Modal组件ComponentA和ComponentB,组件代码结构如下:
<script setup lang="ts"> const model = defineModel({type: Boolean, default: false}) </script> <u-modal v-model="model"> <u-card class="flex flex-col gap-6 py-6"> ... </u-card> </u-modal>
使用useModal()程序化打开模态框时,出现以下问题:
- 同一组件多次打开时,第二个实例会替换第一个:
const modalA1 = useModal(); modalA1.open(ComponentA, options); const modalA2 = useModal(); modalA2.open(ComponentA, options);
- 打开不同组件时,后打开的模态框会覆盖之前的:
const modalA = useModal(); modalA.open(ComponentA, options); const modalB = useModal(); modalB.open(ComponentB, options);
模板中直接嵌套多个模态框可正常工作,但程序化方式无法实现多实例共存,需要解决该问题。
问题原因
Nuxt UI的useModal()默认是单例模式,内部仅维护一个模态框实例,每次调用open方法都会替换当前的组件与配置,导致新模态框覆盖旧的。
解决方案
方案1:自定义多模态框管理器
创建一个支持多实例的composable,手动管理模态框的创建与销毁:
// composables/useMultiModal.ts import { ref, h, render } from 'vue' interface ModalInstance { id: string component: any props: Record<string, any> close: () => void } export const useMultiModal = () => { const modals = ref<ModalInstance[]>([]) const container = document.createElement('div') document.body.appendChild(container) const open = (component: any, props: Record<string, any> = {}) => { // 生成唯一ID区分实例 const id = `modal-${Date.now()}-${Math.random().toString(36).slice(2)}` const vModel = ref(true) const close = () => { vModel.value = false // 等待关闭动画结束后移除实例 setTimeout(() => { modals.value = modals.value.filter(m => m.id !== id) // 重新渲染剩余模态框 render(h('div', {}, modals.value.map(m => h(m.component, { ...m.props, modelValue: true, 'onUpdate:modelValue': (val: boolean) => !val && m.close() })))), container) }, 300) // 匹配Nuxt UI模态框默认关闭动画时长 } const instance: ModalInstance = { id, component, props: { ...props, modelValue: vModel.value, 'onUpdate:modelValue': (val: boolean) => { vModel.value = val !val && close() } }, close } modals.value.push(instance) // 渲染所有当前存在的模态框 render(h('div', {}, modals.value.map(m => h(m.component, m.props))), container) return close } return { open, modals } }
使用方式:
const multiModal = useMultiModal() // 打开多个实例,互不干扰 const closeA1 = multiModal.open(ComponentA, { /* 自定义props */ }) const closeA2 = multiModal.open(ComponentA, { /* 自定义props */ }) const closeB = multiModal.open(ComponentB, { /* 自定义props */ }) // 单独关闭某个模态框 // closeA1()
方案2:模板动态渲染多模态框
在页面模板中用数组管理模态框状态,动态渲染多个独立实例:
<template> <div> <u-modal v-for="modal in modalList" :key="modal.id" v-model="modal.show" > <component :is="modal.component" v-bind="modal.props" /> </u-modal> </div> </template> <script setup lang="ts"> interface ModalItem { id: string component: any props: Record<string, any> show: boolean } const modalList = ref<ModalItem[]>([]) const openModal = (component: any, props: Record<string, any> = {}) => { const id = `modal-${Date.now()}-${Math.random().toString(36).slice(2)}` modalList.value.push({ id, component, props, show: true }) } const closeModal = (id: string) => { const modal = modalList.value.find(m => m.id === id) if (modal) { modal.show = false setTimeout(() => { modalList.value = modalList.value.filter(m => m.id !== id) }, 300) } } // 调用示例 openModal(ComponentA, { /* 自定义props */ }) openModal(ComponentA, { /* 自定义props */ }) openModal(ComponentB, { /* 自定义props */ }) </script>
内容的提问来源于stack exchange,提问作者Sukanta Paul
相关产品推荐
相关产品推荐

