使用Vue方法隐藏Bootstrap模态框

9

我有一个Vue.js组件,它会显示一个带有小表单的模态对话框。当提交表单时,我想隐藏该模态对话框,但无法弄清如何实现。当提交表单时,会在父组件中调用一个方法。

以下是组件代码:

<template>
  <div>
    <div id="todoModal" class="modal fade" role="dialog">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h4 class="modal-title">{{ title }}</h4>
            <button type="button" class="close" data-dismiss="modal">
              &times;
            </button>
          </div>
          <div class="modal-body">
            <form id="todoForm" @submit.prevent="$emit('save')">
              <div class="form-group">
                <label for="name">Todo name</label>
                <input
                  id="name"
                  v-model="todo.name"
                  type="text"
                  class="form-control"
                  aria-describedby="nameHelp"
                  placeholder="Enter Todo Name"
                />
                <small id="nameHelp" class="form-text text-muted"
                  >Enter your todo's name</small
                >
              </div>
            </form>
          </div>
          <div class="modal-footer">
            <button class="btn btn-primary mr-4" type="submit" form="todoForm">
              <span v-if="mode == 'create'">Create</span>
              <span v-if="mode == 'update'">Update</span>
            </button>
            <button
              type="button"
              class="btn btn-danger mr-auto"
              data-dismiss="modal"
              @click="
                $parent.showModal = false;
                $parent.getTodos();
              "
            >
              Cancel
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "CreateTodo",
  props: ["mode", "title", "todo", "showModal"],
  ref: "createTodoModal",
  mounted() {
    if (this.mode == "create") {
      this.title = "Create Todo";
    }
  },
  methods: {}
};
</script>
<style scoped></style>

这是我的APP.js文件

<template>
  <div id="app" class="container mt-5">
    <router-view
      ref="createtodo"
      class="CreateTodo"
      name="a"
      :todo="todo"
      :title="title"
      :mode="mode"
      :show-modal="showModal"
      @save="saveTodo"
    ></router-view>
  </div>
</template>

<script>
import { APIService } from "./APIServices";
const apiService = new APIService();

export default {
  name: "App",
  data: function() {
    return {
      mode: "create",
      title: "Create Todo",
      todo: {},
      todos: [],
      numberOfTodos: 0,
      showModal: false
    };
  },
  mounted: function() {
    this.getTodos();
  },

  methods: {
    saveTodo: function() {
      if (this.mode == "create") {
        apiService.createTodo(this.todo).then(
          result => {
            if (result.status === 200) {
              this.todo = result.data;
              this.getTodos();
            }
          },
          error => {}
        );
        this.showModal = false;
        // this.$refs.createtodo.$refs.todoModal
      } else if (this.mode == "update") {
        apiService.updateTodo(this.todo).then(
          result => {
            this.getTodos();
          },
          error => {}
        );
        this.showModal = false;
      } else if (this.mode == "update") {
        apiService.updateTodo(this.todo).then(
          result => {
            this.showModal = false;
            this.getTodos();
          },
          error => {}
        );
      }
    },
  }
};
</script>

<style lang="scss">
</style>

我尝试使用 ref 引用来自 APP.js 的 Modal,但它无法正常工作。


请检查您的属性“showModal”,它不用于显示/隐藏任何内容。如果没有Bootstrap v-show指令,可以使用。 - David SK
它可以工作,但是当模态隐藏时,模态的黑色背景不会消失。 - Carlos Sosa
8个回答

13

为关闭按钮添加 id 属性

<button type="button" class="close" data-dismiss="modal" aria-label="Close" id="close">
   <span aria-hidden="true">&times;</span>
</button>

然后创建一个关闭模态框的方法:

closeModal() {
   document.getElementById('close').click();
},

11

就像 @Dan Stoian 的回复所说,你可以在 Vue.js 中使用 ref:

<button ref="Close" type="button" data-dismiss="modal" ...>
   ...
</button>

在你的处理程序中

this.$refs.Close.click();

这是一个适用于Vue 3 / Bootstrap 5的优雅解决方案。这完全适合我遇到的情况,其中从模态框中执行的操作(有意)从v-for迭代器中删除了父级。 - DaveL17

7
如果您正在使用bootstrap,需要从中调用隐藏和显示方法,因为模态窗口API会即时创建HTML元素(例如暗色背景)。
我建议创建一个保存方法,而不是调用$emit。在该方法中,可以在发出保存信号之前调用模态窗口的隐藏方法。
<script>
import $ from 'jquery'

export default {
  name: "CreateTodo",
  props: ["mode", "title", "todo"],
  ref: "createTodoModal",
  mounted() {
    if (this.mode == "create") {
      this.title = "Create Todo";
    }
  },
  methods: {
    save() {
       $('#ModalId').modal('hide')
       this.$emit('save')
    }
  }
};
</script>

在这种情况下,不需要使用showModal。


3

子元素

<template>
  <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby=""
    aria-hidden="true" ref="modalEle">
    <div class="modal-dialog modal-dialog-centered">
      <div class="modal-content">
        <div class="modal-header bg-primary text-white">
          <h5 class="modal-title" id="exampleModalLabel">{{ title }}</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <slot name="body" />
        </div>
        <div class="modal-footer">
          <slot name="footer"></slot>
          <button ref="Close" type="button" class="btn btn-secondary" data-bs-dismiss="modal">
            Close
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { onMounted, ref, defineProps, defineExpose } from "vue";
import { Modal } from "bootstrap";

defineProps({
  title: {
    type: String,
    default: "<<Title goes here>>",
  },
});

let modalEle = ref(null);
let thisModalObj = null;

onMounted(() => {
  thisModalObj = new Modal(modalEle.value);
});

function _show() {
  thisModalObj.show();
}

function _close(){
  thisModalObj.hide()
}

defineExpose({ show: _show, close: _close });
</script>

父级元素

<template>
  <Modal title="OMG ITS A MODAL" ref="thisModal">
    <template #body>
      <div class="col-md-12 mx-auto">
        yay modal text
      </div>
    </template>
    <template #footer>
      <!-- extra footer stuff !-->
    </template>
  </Modal>
</template>

<script setup>
import { ref } from 'vue';
import Modal from "../components/ModalCard.vue";

let showModal = ()=>{
  thisModal.value.show();
}

let closeModal = ()=>{
  thisModal.value.close();
}

</script>

解释

基本上我们所做的是通过refs将子函数暴露给父级。在_show和_close函数中,我们触发.show()和.hide(),它们是我们通过thisModalObj访问到的bootstrap模态框函数。希望这可以帮助你!

现在你可以编程调用thisModal.value.show和thisModal.value.close,它会显示并关闭模态框。


1
如何做这个的解释非常棒! - Travis

2
你可以使用v-if来显示/隐藏模态框。
在你的组件中:
  <div v-if="showModal">
    <div id="todoModal" class="modal fade" role="dialog">
    ...
    </div>
  </div>

showModal设置为true/false分别显示/隐藏组件。

最初的回答:

Set showModal to true/false to show/hide component respectively.


嗨Ittus,谢谢你的建议。我尝试了一下,它确实有效,但是当模态隐藏时,模态的背景并没有消失。 - Carlos Sosa
2
如果您正在使用Bootstrap,您需要使用Bootstrap方法来隐藏/显示。 - David SK
这可能会有所帮助 https://dev59.com/Havka4cB1Zd3GeqPoB6k - ittus

1
你可以使用这个npm包。
npm i vue-js-modal

https://www.npmjs.com/package/vue-js-modal

您的代码应该按照以下方式进行修改:
<template>
<modal :name="'edit-modal'+id" height="auto">
    <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Edit {{ mName }}</h5>
        <button type="button" class="close" @click="hideEditModal(id)">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>
    <form action="/user/update" method="patch" @submit.prevent="updateAssistant">
        <div class="modal-body">
            <div class="position-relative form-group">
                <label for="exampleAddress" class="">Full name</label><input name="name" v-model="editName" id="exampleAddress" placeholder="FullName" type="text" class="form-control">
                <div v-if="errors.has('editName')" class="alert alert-danger">
                    {{ errors.first('editName') }}
                </div>
            </div>

            <div class="position-relative form-group">
                <label for="exampleEmail11" class="">Email</label><input name="email" v-model="editEmail" id="exampleEmail11" placeholder="email" type="email" class="form-control">
                <div v-if="errors.has('editEmail')" class="alert alert-danger">
                    {{ errors.first('editEmail') }}
                </div>
            </div>

            <div class="position-relative form-group">
                <label for="examplePassword11" class="">Change Password</label><input name="password" v-model="editPassword" id="examplePassword11" placeholder="password" type="password" class="form-control">
                <div v-if="errors.has('password')" class="alert alert-danger">
                    {{ errors.first('password') }}
                </div>
            </div>
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-secondary" @click="hideEditModal(id)">Close</button>
            <button type="submit" class="btn btn-primary">Save changes</button>
        </div>
        <span class="loader" v-if="this.loading" style="position: absolute; bottom: 0.515rem; left: 20px;">
            <span class="ball-clip-rotate">
                <div style=" border:1px solid #000;"></div>
            </span>
        </span>
    </form>
</modal>

import Errors from '../../Errors.js'
export default {

name: 'AssistantEditModalComponent',

props: [
    'mEmail',
    'mName',
    'id'
],

data () {
    return {
        editPassword: null,
        disabled: false,
        errors: Errors,
        loading: false
    }
},

methods: {
    hideEditModal(id) {
        this.$modal.hide('edit-modal'+id);
    },

    setData() {
        this.editName = this.mName
        this.editEmail = this.mEmail
    },

    updateAssistant() {
        this.disabled = true;
        this.loading = true;
        const form = {
            editName: this.mName,
            editEmail: this.mEmail,
            password: this.editPassword
        }
        axios.patch('/user/update/'+this.id, form)
        .then((response) => {
            this.disabled = false
            this.loading = false
            this.hideEditModal(this.id)
            this.alert(response)
        })
        .catch((err) => {
            this.disabled = false
            this.loading = false
            Errors.fill(err.response.data.errors)
        })
    },

    alert(response) {
        swal(response.data.username, response.data.message, 'success')
    },
},

computed: {
    editName: {
        get: function() {
            return this.mName
        },
        set: function(value) {
            this.$emit('update:mName', value);
        }
    },
    editEmail: {
        get: function() {
            return this.mEmail
        },
        set: function(value) {
            this.$emit('update:mEmail', value);
        }
    }
}}

0

如果您不想添加任何额外的关闭按钮而是使用模态框标题栏的默认X按钮,您可以这样做:

<b-modal
    id="user-role"
    ref="role-modal"
    hide-footer
  >
...
</b-modal>

然后在你的方法中:

hideModal() {
    this.$refs["role-modal"].$refs['close-button'].click()
}

0

对于Vuejs 3,这段代码完美运行:

<template>
<div class="modal fade" id="theModal">
...
</div>
</template>

<script>
import { Modal } from 'bootstrap'

export default {
  data: {
    return {
      theModal: null,
    }
  }
  mounted() {
    this.theModal = new Modal('#theModal');
  },
  methods: {
    hideModal() {
      this.theModal.hide();
    }
  }
}
</script>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接