UniApp全局弹窗实现:基于Vue3的组合式API方案

Viewed 0

在UniApp开发中,全局弹窗是实现跨页面交互的常见需求。本文将介绍一种基于Vue3组合式API的实现方案,通过自定义组件、全局事件监听和provide/inject机制,达到无需手动引入即可在任何页面调用弹窗功能的目的。

核心实现原理

该方案主要围绕三个核心文件构建:

  1. 弹窗组件文件:负责UI呈现和基础交互逻辑。
  2. 全局事件文件:处理跨页面的弹窗触发与通信。
  3. 入口文件配置:用于注册全局方法和组件。

弹窗组件实现

弹窗组件采用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;
}
0 Answers