需求描述: 我希望用户不论在哪个页面,在收到某个消息时都会弹出一个弹窗。
技术原理: vue 中可以在 app.vue 中定义一个弹窗,这个弹窗会在所有组件中上层弹出。但是 uniapp 中不可以,uniapp 自身无法实现在所有页面中弹出自定义组件。
实现方案概述
-
实现一个弹窗组件(vue 文件)
定义一个必要的 props 用来控制弹窗显示隐藏;**
定义一个必要的 emit 用来抛出关闭时要触发的方法。
-
定义管理工具(xxx.ts)
管理工具中暴露打开弹窗方法,后续需要显示弹窗时就调用该方法,方法内部主要做了以下几个内容:
- 创建一个 DOM
- 创建 vue 实例
- vue 实例内部以渲染函数的形式加载前边定义的弹窗组件
- 将 vue 实例挂载到 DOM 上
- vue 实例内部定义 close 方法,通过渲染函数将 close 函数传递给弹窗组件
代码实现
-
定义一个你自己的弹窗组件
// testDialog.vue <template> <van-dialog v-model:show="showDialog"> 测试内容 <view class="close-btn" @click="close"> 关闭 </view> </van-dialog> </template> <script setup lang="ts"> import { ref } from "vue"; const props = defineProps({ // 控制显示隐藏 visible: Boolean, config: { type: Object, default: () => ({}), }, data: { type: Object, default: () => ({}), }, }); // 控制关闭时触发 const emit = defineEmits(["close"]); const showDialog = ref(props.visible); // 关闭弹窗时通知父组件 const close = () => { emit("close"); }; </script> <style lang="scss" scoped></style> -
创建管理工具
// dialogManager.ts import { createApp, h, ref } from 'vue' import TestDialog from './testDialog.vue' // 创建并显示新弹窗 export const showDialog = (options?: { config?: any, data?: any }) => { const config = options?.config || {} const data = options?.data || {} // 创建唯一ID const dialogId = `dialog_${Date.now()}_${Math.random().toString(36).substr(2, 5)}` // 创建容器元素 const container = document.createElement('div') container.id = dialogId document.body.appendChild(container) // 创建应用实例 const app = createApp({ setup() { const visible = ref(true) // 关闭弹窗时卸载 const closeHandler = () => { visible.value = false setTimeout(() => { // 延迟卸载确保动画完成 app.unmount() document.body.removeChild(container) }, 300) } // 渲染弹窗组件 return () => h(TestDialog, { visible: visible.value, onClose: closeHandler }) } }) // 挂载应用 app.mount(container) // 存储实例引用 dialogInstances.value.push({ id: dialogId, container, app, close: () => app.unmount() }) return dialogId }