Vue3+Bootstrap+Pinia全局模态框执行Store操作后无法关闭问题
问题:调用Pinia方法后Bootstrap模态框无法关闭
我制作了一个全局复用的ModalComponent.vue组件,包含标题、主体和页脚插槽,自带的关闭按钮功能正常。现在希望在关闭按钮旁添加一个可调用Pinia Store的动态按钮——比如在商品列表中点击删除图标打开模态框(此功能正常),模态框内的确认按钮可根据场景自定义(保存、继续、删除等)。
目前点击确认按钮调用Store的removeItems方法后,商品已成功从列表中删除,但模态框无法关闭。尝试设置dataModal.value = false(仅背景层残留或无反应)、从Pinia Store触发事件等方法均无效,且无报错和日志输出。
代码片段
ModalComponent.vue
<template> <div id="myModal" class="modal fade" ref="myModal" tabindex="-1" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="myModalLabel"> <slot name="title"></slot> </h5> <button type="button" class="btn-close" @click="hideModal" aria-label="Close"></button> </div> <div class="modal-body"> <slot name="body"></slot> </div> <div class="modal-footer"> <Button :content='$t("buttons.cancel")' variant="btn-danger" icon="x-lg" :circle="false" @click="hideModal" /> <slot name="button"></slot> <!-- 动态按钮插槽 --> </div> </div> </div> </div> </template> <script setup> import { Modal } from 'bootstrap'; import Button from '@/components/Buttons/Button.vue'; import { watchEffect, onMounted, ref } from 'vue' const props = defineProps({ showModal: { type: Boolean, default: false } }); const modalInstance = ref(null); const myModal = ref(null); onMounted(() => { modalInstance.value = new Modal(myModal.value, { backdrop: "static" }); }); watchEffect(() => { if (props.showModal === true && modalInstance.value) { modalInstance.value.show(); } }); const emit = defineEmits('close-modal'); function hideModal() { if (modalInstance.value) { modalInstance.value.hide(); emit('close-modal'); } } </script>
父组件(加载模态框和表格)
<template> <modal-component @close-modal="dataModal = false" :showModal="dataModal"> <template v-slot:title> {{ $t('itemTitle') }} </template> <template v-slot:body> {{ $t('itemBody') }} </template> <template v-slot:button> <Button :content='$t("buttons.delete")' variant="btn-secondary" icon="trash-fill" :circle="false" @click="onDelete" /> </template> </modal-component> <Table /> </template> <script setup> import Button from '@/components/Buttons/Button.vue' import ModalComponent from '@/components/ModalComponent' import { ref, onMounted } from 'vue' import { useItemsStore } from '@/stores/store-items' import { storeToRefs } from 'pinia' const itemsStore = useItemsStore() const { getItems, removeItems } = itemsStore const { isLoading, items } = storeToRefs(itemsStore) getItems() const dataModal = ref(false) const itemToBeDeleted = ref(null) // 需指向选中的待删除商品 async function onDelete(){ await removeItems(itemToBeDeleted.value.id) dataModal.value = false } </script>
Pinia Store文件(store-items.js)
import { defineStore } from "pinia"; import { apiClient } from "@/services/api-client"; export const useItemsStore = defineStore('ItemsStore', { state: () => { return { items: [], isLoading: false } }, actions: { async removeItems(id) { this.isLoading = true; try { const response = await apiClient.RemoveItem({id:id}) const index = this.items.findIndex(item => item.id === id) if (index !== -1) { this.items.splice(index, 1); } this.isLoading = false; return response.success } catch (error) { this.isLoading = false; throw error } } } })
解决方法
1. 异步等待Pinia操作完成后关闭模态框
removeItems是异步方法,需要等待它执行完成后再修改dataModal状态,确保DOM更新和模态框关闭逻辑同步:
async function onDelete(){ await removeItems(itemToBeDeleted.value.id) dataModal.value = false }
2. 完善模态框的双向状态监听
原watchEffect只处理了showModal为true的情况,添加对false状态的处理,确保父组件状态变化能同步到模态框实例:
watchEffect(() => { if (modalInstance.value) { props.showModal ? modalInstance.value.show() : modalInstance.value.hide() } });
3. 优化Pinia中的数据更新逻辑
用findIndex替代循环查找,提升代码效率,同时改用async/await替代then,让异步逻辑更清晰。
4. 移除不必要的mitt事件
原代码中用mitt触发item-deleted事件,但父组件未正确监听该事件(且异步等待的方式更直接),可删除相关代码简化逻辑。
内容的提问来源于stack exchange,提问作者R-b-n
相关产品推荐
相关产品推荐

