Vue3 + TypeScript 控制弹框及数据传输实现

弹框组件封装

创建一个可复用的弹框组件 Modal.vue,使用 definePropsdefineEmits 进行类型定义:

<template>
  <div v-if="visible" class="modal-mask">
    <div class="modal-container">
      <slot name="header"></slot>
      <slot name="body"></slot>
      <button @click="$emit('close')">关闭</button>
    </div>
  </div>
</template>

<script setup lang="ts">
defineProps<{
  visible: boolean
}>()

defineEmits<{
  (e: 'close'): void
}>()
</script>

父组件调用逻辑

在父组件中通过 ref 控制弹框显隐,并传递数据:

<template>
  <button @click="showModal">打开弹框</button>
  <Modal :visible="isVisible" @close="hideModal">
    <template #header>
      <h2>{{ modalData.title }}</h2>
    </template>
    <template #body>
      <p>{{ modalData.content }}</p>
    </template>
  </Modal>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Modal from './Modal.vue'

interface ModalData {
  title: string
  content: string
}

const isVisible = ref(false)
const modalData = ref<ModalData>({
  title: '默认标题',
  content: '默认内容'
})

const showModal = (data: ModalData) => {
  modalData.value = data
  isVisible.value = true
}

const hideModal = () => {
  isVisible.value = false
}
</script>

跨组件通信方案

对于复杂场景可使用 provide/inject

// 父组件
import { provide, ref } from 'vue'
const modalControl = ref(false)
provide('modalControl', modalControl)

// 子组件
import { inject } from 'vue'
const modalVisible = inject<Ref<boolean>>('modalControl')

事件总线替代方案

安装 mitt 库实现全局事件:

npm install mitt

创建事件中心:

// eventBus.ts
import mitt from 'mitt'
type Events = {
  'show-modal': { title: string; content: string }
}
export const emitter = mitt<Events>()

组件中使用:

// 发送方
emitter.emit('show-modal', { title: '测试', content: '内容' })

// 接收方
emitter.on('show-modal', (data) => {
  modalData.value = data
  isVisible.value = true
})

类型安全增强

为弹框组件添加完整的类型定义:

interface ModalProps {
  visible: boolean
  size?: 'sm' | 'md' | 'lg'
}

interface ModalEmits {
  (e: 'close'): void
  (e: 'confirm', payload: unknown): void
}

动态组件方案

使用 component :is 实现动态弹框内容:

<component :is="currentModal" v-bind="modalProps" @close="hideModal" />

注意事项
  1. 弹框组件应设置 z-index 和定位样式
  2. 通过 @keyup.escape 监听 ESC 键关闭
  3. 添加 beforeUnmount 事件清理
  4. 使用 Teleport 组件避免 DOM 层级问题

完整示例应包含样式处理和动画效果,可通过 transition 组件实现平滑的显隐过渡。这种实现方式在 Vue3 组合式 API 下具有更好的类型推断和代码组织能力。

更多推荐