使用 Vue3 + Composition API 开发一个可复用的模态弹窗组件(附完整代码)

在日常开发中,弹窗是 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 构建一个功能完善、可复用、灵活扩展的弹窗组件,不仅适用于小型组件库,也适合企业项目中的实际使用。

相关推荐
计算机毕设VX:Fegn08957 小时前
计算机毕业设计|基于springboot + vue蛋糕店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
没差c8 小时前
springboot集成flyway
java·spring boot·后端
三水不滴8 小时前
Redis 过期删除与内存淘汰机制
数据库·经验分享·redis·笔记·后端·缓存
笨蛋不要掉眼泪9 小时前
Spring Boot集成LangChain4j:与大模型对话的极速入门
java·人工智能·后端·spring·langchain
sheji341612 小时前
【开题答辩全过程】以 基于SpringBoot的疗养院管理系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
短剑重铸之日12 小时前
《设计模式》第六篇:装饰器模式
java·后端·设计模式·装饰器模式
码界奇点13 小时前
基于Flask与OpenSSL的自签证书管理系统设计与实现
后端·python·flask·毕业设计·飞书·源代码管理
代码匠心14 小时前
从零开始学Flink:状态管理与容错机制
java·大数据·后端·flink·大数据处理
分享牛14 小时前
LangChain4j从入门到精通-11-结构化输出
后端·python·flask
知识即是力量ol15 小时前
在客户端直接上传文件到OSS
java·后端·客户端·阿里云oss·客户端直传