使用Vue 3 + Bootstrap + Pinia的全局模态

zf9nrax1  于 2023-03-24  发布在  Vue.js
关注(0)|答案(2)|浏览(80)

我已经做了一个ModalComponent.vue文件,我想在任何地方重复使用。模态有标题,主体和页脚的插槽。它有一个标准的关闭模态按钮,它工作正常。
我想在它旁边再加一个按钮,用来打电话到我的皮尼亚商店。
例如,我有一个包含项目的表。我想删除一个项目。我点击垃圾桶图标,模态打开(这适用于特定的项目)。
在模态内,我有确认按钮,可以为每个表不同(保存,继续,删除等)。
所以现在,我想删除特定的项目。点击组件中的按钮,商店被调用并正确地删除项目(我看到它发生在背景下的表格中)。
现在我想要模态关闭。所以在商店电话之后,我想要模态关闭。我已经尝试了阳光下的一切,但它不是关闭。
我试着把dataModal.value设置为false,什么都没有发生,或者只是背景仍然存在。我试着从Pinia商店发出一个事件,什么都没有。没有错误,没有console.logs..
我怎样才能做到这一点?
下面是我的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> // here is where the dynamic button will be placed
            </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);
    
    onMounted(() => {
      modalInstance.value = new Modal(document.getElementById('myModal'), {
        target: "#myModal",
        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" @item-deleted="dataModal = false">
      <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 { computed, ref, watch, onMounted } from 'vue'
import { useItemsStore } from '@/stores/store-items'
import { storeToRefs } from 'pinia'

const { getItems, addItems, removeItems, updateItems } = useItemsStore()

const { isLoading, items } = storeToRefs(useItemsStore())

getItems()

const dataModal = ref(false)

function onDelete(){
  removeItems(itemToBeDeleted.id) // <-- call to the store
  getItems(); 
}

</script>

以下是我的Pinia存储文件:

import { defineStore } from "pinia";
import { apiClient } from "@/services/api-client";
import mitt from 'mitt'

const emitter = mitt()

export const useItemsStore = defineStore('ItemsStore', {
    state: () => {
        return {
            items: [],
            isLoading: false
        }
    },
 
    actions: {
        
        async removeItems(id) {
            this.isLoading = true;
            
            return apiClient.RemoveItem({id:id})
                .then(response => {
                    // if(!hasError(dispatch, commit, response)){
                        let index = 0;
                        for(let i=0; i < this.items.length; i++){
                            if(this.items[i].id === id){
                                index = i;
                            }   
                        }
                    
                        this.items.splice(index, 1);
                        this.isLoading = false;

                        emitter.emit('item-deleted')

                        return response.succes
                    // }
                    //
                    // return false;
                })
        }
    }
})
xtfmy6hx

xtfmy6hx1#

data-modal是否控制你的modal的显示,如果是,则输入:
dataModal.value = false
在调用函数'removeItems'之后,甚至在函数'onDelete'中的'getItems'之后。
如果不是这样的话,在你的脚本中创建一个引用'showModal',并使用'v-show'或'v-if'来控制你的模型的可见性

envsm3lx

envsm3lx2#

好了,经过16个小时的慢慢疯狂,这里是我的不那么干净但工作的解决方案。这段代码显示和隐藏了Bootstrap 5模式的过渡和背景:
ModalComponent.vue:

<template>
  <div :id="id" 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({
  id: {
    type: String
  }
});

const modalInstance = ref(null);

const emit = defineEmits(['get-modal'])

onMounted(() => {
  modalInstance.value = new Modal(document.getElementById(props.id), {
    target: props.id,
    backdrop: "static",
  });

  emit('get-modal', modalInstance.value)
});


function hideModal() {
  if (modalInstance.value) {
    modalInstance.value.hide();
  }
}

</script>

调用模态组件的组件:

<template>

    <modal-component @get-modal="modalGetted" :id="'deleteItemmodal'">
      <template v-slot:title>
        {{ $t('ModalTitle') }}
      </template>
      <template v-slot:body>
        {{ $t('ModalBody') }}
      </template>
      <template v-slot:button>
        <Button :content='$t("buttons.delete")' variant="btn-secondary" icon="trash-fill" :circle="false" @click="onDelete" />
      </template>
    </modal-component>
    
</template>

<script setup>
import Button from '@/components/Buttons/Button.vue'
import ModalComponent from '@/components/ModalComponent'

const { isLoading, items } = storeToRefs(useItemsStore())

let modalInstance = ref(null)

function modalGetted(modal) {
  modalInstance = modal // set the modal
}

function onShowDeleteModal(item) {
  itemToBeDeleted = item
  modalInstance.show() //show the modal
}

function onDelete(){
  removeItems(itemToBeDeleted.id)
  modalInstance.hide() // hide the modal
  getItems();
}

</script>

相关问题