编程 uni-app 也能实现全局 Toast?这套方案彻底搞定!

2025-08-17 18:33:39 +0800 CST views 154

uni-app 也能实现全局 Toast?这套方案彻底搞定!

在日常的 uni-app 开发中,你是否遇到过这样的场景:

  • 网络请求失败时需要给用户一个全局提示;
  • 路由守卫中想要提醒用户“请先登录”;
  • 或者在业务逻辑深处,需要快速弹出一个 Toast。

问题是:uni-app 没有开箱即用的全局 Toast 方案uni.showToast() 功能太简单,样式难自定义;组件化的 Toast 又只能在当前页面使用,无法跨组件调用。

本文将带你实现一套完整的全局 Toast 解决方案,并且还能扩展到全局 Loading、MessageBox —— 真正做到 随时随地调用


一、问题分析

传统方案的局限性主要在于:

  1. uni.showToast()

    • 优点:调用方便。
    • 缺点:样式固定,无法扩展。
  2. 组件化 Toast

    • 优点:可定制。
    • 缺点:只能在当前组件调用,没法跨页面使用。
  3. Wot UI 的 useToast

    • 优点:函数式调用简洁。
    • 缺点:必须在 setup 顶层调用,无法在请求拦截器、路由守卫中使用。

核心原因在于:uni-app 不支持像 Vue3 一样挂载全局组件实例,因此无法在任意位置访问组件。


二、解决方案架构

要想解决这个问题,我们可以分三步:

  1. wd-toast 组件:提供基础能力;
  2. Layout 插件:一次性插入全局组件;
  3. useGlobalToast + Pinia:用状态管理来驱动 Toast,在任何地方都能调用。

三、实现步骤

1. 使用 wd-toast 组件

Wot UI 的 Toast 组件提供了函数式调用。

<script setup>
const toast = useToast('myToast')

// 显示提示
toast.show({
  msg: '这是一个提示',
  duration: 2000
})
</script>

<template>
  <wd-toast selector="myToast" />
</template>

但这样仍有局限:必须写在 setup 顶层,无法全局调用。


2. Layout 插件:一次插入,全局可用

layouts/default.vue 中统一插入全局组件:

<template>
  <wd-config-provider>
    <slot />
    <wd-toast />
    <global-toast />
    <global-loading />
    <global-message />
  </wd-config-provider>
</template>

这样所有页面都会自带这些全局组件,实现了“全局挂载”。


3. useGlobalToast + Pinia:全局状态驱动

我们用 Pinia 管理 Toast 的状态:

// useGlobalToast.ts
import { defineStore } from 'pinia'

export const useGlobalToast = defineStore('global-toast', {
  state: () => ({
    toastOptions: { show: false, duration: 2000 },
    currentPage: '',
  }),
  actions: {
    show(option) {
      this.currentPage = getCurrentPath()
      this.toastOptions = {
        ...this.toastOptions,
        ...(typeof option === 'string' ? { msg: option } : option),
        show: true,
      }
    },
    success(msg) {
      this.show({ msg, iconName: 'success', duration: 1500 })
    },
    error(msg) {
      this.show({ msg, iconName: 'error', direction: 'vertical' })
    },
    warning(msg) {
      this.show({ msg, iconName: 'warning' })
    },
    close() {
      this.toastOptions = { show: false, duration: 2000 }
    },
  },
})

全局组件 GlobalToast.vue 监听 toastOptions 的变化来显示/关闭 Toast。

<script setup>
const { toastOptions, currentPage } = storeToRefs(useGlobalToast())
const toast = useToast('globalToast')

watch(toastOptions, (opt) => {
  if (opt.show && currentPage.value === getCurrentPath())
    toast.show(opt)
  else
    toast.close()
})
</script>

<template>
  <wd-toast selector="globalToast" />
</template>

四、使用示例

在组件中使用

const globalToast = useGlobalToast()

globalToast.success('操作成功!')
globalToast.error('操作失败!')

在请求拦截器中使用

uni.addInterceptor('request', {
  fail() {
    useGlobalToast().error('网络请求失败')
  }
})

在路由守卫中使用

if (!isLogin()) {
  useGlobalToast().warning('请先登录')
  uni.navigateTo({ url: '/pages/login/index' })
  return false
}

五、扩展功能

基于相同思路,还能实现:

  • GlobalLoading:显示全局加载提示;
  • GlobalMessage:全局弹窗(alert、confirm);
  • Notify/MessageBox:快速拓展到更多交互场景。

六、总结

通过这套架构,我们实现了:

  1. 真正的全局调用:拦截器、守卫、任意逻辑中都能使用;
  2. 多端兼容:兼容小程序、H5、APP;
  3. 页面隔离:只在当前页面显示,不会出现跨页面混乱;
  4. 可扩展性强:同样的架构轻松扩展到 Loading、MessageBox。

如果你也在为 uni-app 全局 Toast 而烦恼,不妨试试这套方案。它不仅优雅,而且高度可扩展,让全局提示不再是难题! 🚀

推荐文章

如何在 Linux 系统上安装字体
2025-02-27 09:23:03 +0800 CST
向满屏的 Import 语句说再见!
2024-11-18 12:20:51 +0800 CST
Go 1.23 中的新包:unique
2024-11-18 12:32:57 +0800 CST
Nginx 反向代理
2024-11-19 08:02:10 +0800 CST
Dropzone.js实现文件拖放上传功能
2024-11-18 18:28:02 +0800 CST
Vue3中如何处理状态管理?
2024-11-17 07:13:45 +0800 CST
H5端向App端通信(Uniapp 必会)
2025-02-20 10:32:26 +0800 CST
Rust async/await 异步运行时
2024-11-18 19:04:17 +0800 CST
ElasticSearch 结构
2024-11-18 10:05:24 +0800 CST
10个极其有用的前端库
2024-11-19 09:41:20 +0800 CST
使用xshell上传和下载文件
2024-11-18 12:55:11 +0800 CST
2024年微信小程序开发价格概览
2024-11-19 06:40:52 +0800 CST
curl错误代码表
2024-11-17 09:34:46 +0800 CST
JavaScript设计模式:单例模式
2024-11-18 10:57:41 +0800 CST
thinkphp swoole websocket 结合的demo
2024-11-18 10:18:17 +0800 CST
使用 Git 制作升级包
2024-11-19 02:19:48 +0800 CST
程序员茄子在线接单