在UniApp开发中,全局弹窗是实现跨页面交互的常见需求。本文将介绍一种基于Vue3组合式API的实现方案,通过自定义组件、全局事件监听和provide/inject机制,达到无需手动引入即可在任何页面调用弹窗功能的目的。
核心实现原理
该方案主要围绕三个核心文件构建:
- 弹窗组件文件:负责UI呈现和基础交互逻辑。
- 全局事件文件:处理跨页面的弹窗触发与通信。
- 入口文件配置:用于注册全局方法和组件。
弹窗组件实现
弹窗组件采用Vue3的<script setup>语法,核心是控制弹窗的显示与隐藏,并提供确认、取消等事件回调。
<template>
<view v-if="visible" class="popup-mask" @tap="close">
<view class="popup-content" @tap.stop>
<view class="popup-header">
<text>{{ title }}</text>
<uni-icons type="closeempty" size="24" color="#999" @click="close"></uni-icons>
</view>
<view class="popup-body">
<slot></slot>
</view>
<view class="popup-footer">
<button v-if="showCancel" class="cancel-btn" @click="handleCancel">{{ cancelText }}</button>
<button class="confirm-btn" @click="handleConfirm">{{ confirmText }}</button>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
title: { type: String, default: '提示' },
cancelText: { type: String, default: '取消' },
confirmText: { type: String, default: '确定' },
showCancel: { type: Boolean, default: true }
})
const emit = defineEmits(['confirm', 'cancel', 'close'])
const visible = ref(false)
const open = () => visible.value = true
const close = () => {
visible.value = false
emit('close')
}
const handleConfirm = () => {
emit('confirm')
close()
}
const handleCancel = () => {
emit('cancel')
close()
}
defineExpose({ open, close })
</script>
<style scoped>
/* 样式代码省略 */
</style>
全局事件处理
全局事件文件通过Vue插件机制安装,将弹窗方法挂载到全局属性上,并利用provide/inject实现跨层级访问。
import { getCurrentInstance } from 'vue'
export default {
install(app) {
const popup = {
show(options) {
const instance = getCurrentInstance()
if (instance && instance.proxy) {
return instance.proxy.$popup(options)
}
console.warn('Popup: Cannot get current instance')
},
hide() {
const instance = getCurrentInstance()
if (instance && instance.proxy) {
instance.proxy.$popup.close()
}
}
}
app.config.globalProperties.$popup = popup
app.provide('popup', popup)
}
}
入口文件配置
在应用入口文件中,安装上述全局事件插件,确保弹窗功能在应用启动时即可使用。
import { createSSRApp } from 'vue'
import App from './App.vue'
import popup from './utils/popup'
export function createApp() {
const app = createSSRApp(App)
app.use(popup)
return { app }
}
使用方式
选项式API调用
在选项式API中,可以直接通过this.$popup调用弹窗,并利用Promise处理用户操作结果。
this.$popup.show({
title: '确认删除',
content: '确定要删除这条数据吗?'
}).then(confirmed => {
if (confirmed) {
// 用户点击确定后的逻辑
}
})
组合式API调用
在组合式API中,可以通过inject方法获取弹窗实例,实现更灵活的调用。
const { show } = inject('popup')
show({ title: '提示', content: '操作成功' })
方案特点
本实现方案具备以下突出特点:
- 全局调用:无需在每个页面单独引入组件,通过全局方法即可触发。
- 异步处理:提供Promise接口,方便处理用户的确认与取消操作。
- 高度定制:支持自定义弹窗标题、内容、按钮文本及显示逻辑。
- 类型安全:结合TypeScript可提供完善的类型提示,减少编码错误。
- 健壮的错误处理:内置实例检测,避免在未正确上下文中调用导致的运行时问题。
样式定制建议
弹窗样式可以通过CSS类名轻松覆盖,以适应不同的设计需求。例如,修改背景色或调整按钮样式。
/* 修改弹窗内容区域背景色 */
.popup-content {
background-color: #f8f8f8;
}
/* 调整确认按钮样式 */
.confirm-btn {
color: #007aff;
font-weight: bold;
}