在日常开发中,弹窗是 UI 交互中非常常见的组件,本文将带你从 0 构建一个 可复用、支持多种内容、支持嵌套与异步处理的模态弹窗组件,并基于 Vue 3 的 Composition API 实现代码清晰、功能强大且易于维护的结构。
📦 技术栈说明
- Vue 3.x
- Composition API
<Teleport />
组件传送内容至 body- 动画:CSS 动画或第三方库(如 animate.css)
🧱 组件目标功能
- ✅ 基础弹窗显示/隐藏
- ✅ 支持自定义内容插槽
- ✅ 支持关闭事件回调
- ✅ 支持遮罩层点击关闭
- ✅ 支持外部控制 & 全局调用
🗂 目录结构建议
css
css
复制编辑
src/
└── components/
└── Modal.vue
└── useModal.js
🔧 Modal.vue 组件实现
xml
vue
复制编辑
<template>
<Teleport to="body">
<div v-if="visible" class="modal-mask" @click.self="handleClose">
<div class="modal-container">
<slot />
<button class="close-btn" @click="handleClose">×</button>
</div>
</div>
</Teleport>
</template>
<script setup>
import { defineProps, defineEmits, watch } from 'vue'
const props = defineProps({
modelValue: Boolean
})
const emit = defineEmits(['update:modelValue', 'close'])
const visible = $computed(() => props.modelValue)
function handleClose() {
emit('update:modelValue', false)
emit('close')
}
</script>
<style scoped>
.modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
}
.modal-container {
background: white;
padding: 20px;
border-radius: 8px;
position: relative;
}
.close-btn {
position: absolute;
top: 5px;
right: 10px;
background: none;
border: none;
font-size: 18px;
}
</style>
🌱 使用方式
xml
vue
复制编辑
<template>
<button @click="show = true">打开弹窗</button>
<Modal v-model="show" @close="onClose">
<h3>自定义内容</h3>
<p>这是弹窗的内容区</p>
</Modal>
</template>
<script setup>
import { ref } from 'vue'
import Modal from '@/components/Modal.vue'
const show = ref(false)
const onClose = () => {
console.log('弹窗关闭了')
}
</script>
🧩 useModal:组合式 API 封装调用
arduino
js
复制编辑
import { ref } from 'vue'
export function useModal() {
const isVisible = ref(false)
const open = () => { isVisible.value = true }
const close = () => { isVisible.value = false }
return {
isVisible,
open,
close
}
}
使用示例:
xml
vue
复制编辑
<script setup>
import { useModal } from '@/components/useModal'
import Modal from '@/components/Modal.vue'
const { isVisible, open, close } = useModal()
</script>
<template>
<button @click="open">全局弹窗</button>
<Modal v-model="isVisible" @close="close">
<p>全局控制的弹窗</p>
</Modal>
</template>
💡 提升建议
- 添加过渡动画
transition
- 支持键盘 ESC 关闭
- 支持嵌套弹窗管理
- 异步确认(如:确认删除操作)
✅ 总结
通过本文,你可以掌握如何在 Vue3 项目中使用 <Teleport>
和 Composition API
构建一个功能完善、可复用、灵活扩展的弹窗组件,不仅适用于小型组件库,也适合企业项目中的实际使用。