vue3.0实现弹窗
使用 Vue 3.0 实现弹窗功能
基于 Teleport 和 Composition API 的弹窗组件
创建一个可复用的弹窗组件,利用 Vue 3 的 Teleport 将弹窗内容挂载到 body 下,避免样式污染。
<!-- Modal.vue -->
<template>
<Teleport to="body">
<div v-if="isOpen" class="modal-overlay" @click.self="close">
<div class="modal-content">
<slot></slot>
<button @click="close">关闭</button>
</div>
</div>
</Teleport>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
modelValue: Boolean
})
const emit = defineEmits(['update:modelValue'])
const isOpen = ref(false)
function open() {
isOpen.value = true
}
function close() {
isOpen.value = false
emit('update:modelValue', false)
}
defineExpose({
open,
close
})
</script>
<style scoped>
.modal-overlay {
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-content {
background: white;
padding: 20px;
border-radius: 8px;
max-width: 80%;
}
</style>
在父组件中使用弹窗
通过 v-model 控制弹窗显示隐藏,也可以通过 ref 调用组件暴露的方法。
<!-- ParentComponent.vue -->
<template>
<div>
<button @click="showModal">打开弹窗</button>
<Modal v-model="modalVisible">
<h2>弹窗标题</h2>
<p>这是弹窗内容</p>
</Modal>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Modal from './Modal.vue'
const modalVisible = ref(false)
const modalRef = ref(null)
function showModal() {
modalVisible.value = true
// 或者直接调用组件方法
// modalRef.value.open()
}
</script>
使用 provide/inject 实现全局弹窗控制
创建一个全局弹窗服务,方便在任何组件中调用。
// modalService.js
import { ref, provide, inject } from 'vue'
const ModalSymbol = Symbol()
export function provideModal() {
const isOpen = ref(false)
const content = ref(null)
function open(component, props) {
content.value = { component, props }
isOpen.value = true
}
function close() {
isOpen.value = false
}
provide(ModalSymbol, {
isOpen,
content,
open,
close
})
}
export function useModal() {
const modal = inject(ModalSymbol)
if (!modal) throw new Error('Modal provider not found')
return modal
}
全局弹窗组件实现
<!-- GlobalModal.vue -->
<template>
<Teleport to="body">
<div v-if="isOpen" class="modal-overlay" @click.self="close">
<div class="modal-content">
<component :is="content.component" v-bind="content.props" />
<button @click="close">关闭</button>
</div>
</div>
</Teleport>
</template>
<script setup>
import { useModal } from './modalService'
const { isOpen, content, close } = useModal()
</script>
在应用中使用全局弹窗
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import { provideModal } from './modalService'
import GlobalModal from './GlobalModal.vue'
const app = createApp(App)
app.component('GlobalModal', GlobalModal)
app.provideModal = provideModal
app.mount('#app')
<!-- SomeComponent.vue -->
<template>
<button @click="showAlert">显示全局弹窗</button>
</template>
<script setup>
import { useModal } from './modalService'
import AlertComponent from './AlertComponent.vue'
const modal = useModal()
function showAlert() {
modal.open(AlertComponent, {
message: '这是一个全局弹窗!'
})
}
</script>
弹窗动画效果
为弹窗添加过渡动画,提升用户体验。
<template>
<Teleport to="body">
<Transition name="modal">
<div v-if="isOpen" class="modal-overlay" @click.self="close">
<div class="modal-content">
<slot></slot>
</div>
</div>
</Transition>
</Teleport>
</template>
<style scoped>
.modal-enter-active,
.modal-leave-active {
transition: opacity 0.3s ease;
}
.modal-enter-from,
.modal-leave-to {
opacity: 0;
}
.modal-content {
transition: transform 0.3s ease;
}
.modal-enter-active .modal-content {
transition: all 0.3s ease;
}
.modal-enter-from .modal-content,
.modal-leave-to .modal-content {
transform: scale(0.9);
}
</style>
这些方法涵盖了 Vue 3 中实现弹窗的主要技术方案,可以根据项目需求选择适合的方式。







