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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 07:27:02