Vue3组合式API模态框开关异常及ESC按键监听需求
解决Vue3组合式API模态框的开关问题(含ESC关闭支持)
我来帮你一步步排查并解决这些问题,咱们先从根源找起:
一、修复v-if无法打开模态框的问题
你的代码里有两个关键的模板错误导致了这个问题:
- 多余的
@click绑定:你在<announcement-modal>标签上加了@click="isModalOpen = true",这不仅没必要,还可能干扰模态框的状态切换; - 标签闭合错误:App.vue的模板开头只有一个
<div>,结尾却多写了两个</div>,这会破坏Vue的模板解析逻辑,导致组件渲染异常。
修复后的App.vue模板部分:
<template> <div class="min-h-screen flex items-center justify-center"> <button @click="isModalOpen = true" type="button" class="btn btn-blue">Open Modal</button> <announcement-modal v-if="isModalOpen" v-model:isOpen="isModalOpen"></announcement-modal> </div> </template>
另外注意:你导入的组件是AnnouncementModal,但子组件文件名是Announcement.vue,这大概率是笔误,建议把子组件文件名改成AnnouncementModal.vue,保持命名一致避免混淆。
二、修复v-show下关闭按钮失效的问题
关闭按钮失效的核心原因是事件冒泡:你之前在模态框组件上绑定的@click="isModalOpen = true",会在点击关闭按钮时触发冒泡事件,把isModalOpen重新设为true,直接抵消了关闭操作。
解决方法就是去掉组件上多余的@click绑定,同时修正子组件的模板闭合错误(你的子组件多写了两个</div>)。
三、添加ESC按键关闭功能及卸载时移除监听
我们可以在子组件的setup中添加全局键盘监听,捕获ESC键触发关闭逻辑,同时在组件卸载时移除监听,避免内存泄漏。
修改后的子组件(AnnouncementModal.vue)完整代码:
<template> <!-- 添加遮罩层,点击遮罩也能关闭模态框 --> <div class="modal-overlay" @click="closeModal"> <div class="modal-content text-center" @click.stop> <button @click="closeModal" type="button" class="btn btn-blue"> Dismiss </button> </div> </div> </template> <script> import { onUnmounted } from "vue" export default { props: ["isOpen"], // 显式声明emits,符合Vue3最佳实践,避免警告 emits: ["update:isOpen"], setup(props, context) { // 监听ESC按键 const handleEscKey = (e) => { if (e.key === 'Escape' || e.keyCode === 27) { closeModal() } } // 组件挂载后添加全局监听 window.addEventListener('keydown', handleEscKey) // 组件卸载时移除监听,防止内存泄漏 onUnmounted(() => { console.log("after unmounted") window.removeEventListener('keydown', handleEscKey) }); const closeModal = () => { // 触发v-model的更新事件,注意驼峰命名对应 context.emit("update:isOpen", false); } return { closeModal } } } </script> <style scoped> /* 给模态框添加基础样式,让它更符合视觉预期 */ .modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; } .modal-content { background-color: white; padding: 2rem; border-radius: 8px; } </style>
这里的@click.stop是为了阻止模态框内容区域的点击事件冒泡到遮罩层,避免点击按钮或内容时意外关闭模态框。
最终完整的App.vue代码
<template> <div class="min-h-screen flex items-center justify-center"> <button @click="isModalOpen = true" type="button" class="btn btn-blue">Open Modal</button> <announcement-modal v-if="isModalOpen" v-model:isOpen="isModalOpen"></announcement-modal> </div> </template> <script> import { ref } from "vue"; import AnnouncementModal from "./components/AnnouncementModal"; export default { components: { AnnouncementModal, }, setup() { const isModalOpen = ref(false); return { isModalOpen, } }, } </script>
现在你的模态框应该可以正常开关,按下ESC键也能关闭,组件卸载时也会自动移除键盘监听啦。
内容的提问来源于stack exchange,提问作者user3541631
相关产品推荐
相关产品推荐

