uni-app全局提示终极方案:uView Pro的useToast与useModal完全解析

更新日期: 2026-04-02 阅读: 8 标签: uniapp

在uni-app开发中,你是否曾被uni.showToast和uni.showModal的各种限制折磨得痛不欲生?本文将带你深入了解uView Pro如何通过useToast和useModal彻底解决这些痛点,并介绍两种实现全局提示的可行方案。


一、uni-app官方API的痛点

1.1 uni-app没有真正的根组件

这是一个很多开发者忽略但非常重要的问题:

  • App.vue不是根组件:它只是应用入口文件,不会作为Vue的根组件渲染

  • 页面是独立的:每个pages下的页面都是独立的Vue实例,相互之间无法共享状态

  • 全局组件难以实现:想在所有页面显示同一个Toast或Modal,技术上非常困难

这导致了一个根本性问题:uni-app官方无法提供真正的全局Toast和Modal解决方案。

1.2 uni.showToast的困境

uni.showToast看似简单:

uni.showToast({
  title: '加载中...',
  icon: 'loading'
})

但实际开发中,这些问题会让你崩溃:

痛点具体表现
全局单例只能显示一个Toast,多个请求时互相覆盖
样式固定位置、文字、背景色全部无法自定义
类型单一只有loading、success、none、error四种
无法管理不能控制显示顺序,不能手动关闭(loading除外)

典型场景:用户上传多个文件时,每个文件的进度提示会相互覆盖,最后用户只能看到最后一个提示。

1.3 uni.showModal的痛点

uni.showModal({
  title: '确认删除?',
  content: '删除后数据无法恢复',
  success(res) {
    if (res.confirm) {
      // 确认逻辑
      // 如果这里还要弹窗,就是回调嵌套
    }
  }
})

存在的问题:

  • 回调嵌套:多个弹窗组合使用时,代码变成"回调地狱"

  • 样式受限:按钮颜色、文字、大小都无法自定义

  • 功能单一:不支持输入框、选择列表等复杂交互

  • 平台差异:不同端表现不一致,可能需要额外适配



二、uView Pro的提示、弹窗解决方案

uView Pro是全面支持Vue3.0、TypeScript的uni-app生态框架,提供了80+精选UI组件、便捷工具、常用模板,支持多主题、暗黑模式、国际化,全面支持H5/APP/鸿蒙/小程序多端开发。

2.1 useToast:多实例、灵活可控

uView Pro提供的useToast是真正的"游戏规则改变者":

import { useToast } from 'uview-pro'

const toast1 = useToast({ page: 'upload' })
const toast2 = useToast({ page: 'network' })
const toast3 = useToast({ page: 'toast' })

// 多个Toast同时显示,互不干扰
toast1.show({ title: '上传中...', type: 'loading', position: 'top' })
toast2.show({ title: '网络波动', type: 'warning', position: 'center' })
toast3.show({ title: '上传成功', type: 'success', position: 'bottom' })

核心优势:

特性说明
多实例支持通过pageId可以在同一页面创建多个独立实例
全局模式应用级唯一实例,整个应用共享
局部模式页面级实例,互不干扰
位置灵活top、center、bottom三种位置
类型丰富loading、success、error、warning、info
完全可控可手动控制显示和关闭
样式自定义背景色、文字色、圆角、透明度都可调整

三种调用方式:

// 全局模式 - 整个应用共享一个Toast实例
const globalToast = useToast()

// 局部模式 - 当前页面独立实例
const pageToast = useToast({ page: true })

// 自定义pageId - 页面中多个独立实例
const topToast = useToast({ page: 'topArea' })
const bottomToast = useToast({ page: 'bottomArea' })

pageId实现多实例的原理:

当你在页面中放置多个<u-toast />组件,并通过pageId区分时,每个Toast实例都是完全独立的:

<template>
  <view>
    <u-toast page="topArea" />
    <u-toast page="bottomArea" />
  </view>
</template>

<script setup>
// 不同区域的Toast互不干扰
const topToast = useToast({ page: 'topArea' })
const bottomToast = useToast({ page: 'bottomArea' })

topToast.show({ title: '注意:网络波动', type: 'warning', position: 'top' })
bottomToast.show({ title: '保存成功', type: 'success', position: 'bottom' })
</script>

pageId匹配机制:

useToast调用方式Toast组件是否响应说明
useToast({ page: 'topArea' })<u-toast page="topArea" />精确匹配
useToast({ page: 'topArea' })<u-toast page />未指定pageId,不匹配
useToast({ page: true })<u-toast page />使用当前页面路由作为pageId
useToast()<u-toast global />全局模式

2.2 useModal:函数式调用,灵活可控

uView Pro的useModal提供简洁的模态框显示功能:

import { useModal } from 'uview-pro'

const modal = useModal()

// 单按钮弹窗
modal.show({
  title: '操作成功',
  content: '您的订单已提交成功'
})

// 双按钮确认弹窗
modal.confirm({
  title: '确认删除?',
  content: '删除后数据无法恢复',
  onConfirm: () => {
    console.log('用户点击了确认')
  },
  onCancel: () => {
    console.log('用户点击了取消')
  }
})

useModal特性:

特性说明
多实例支持通过pageId可以在同一页面创建多个独立Modal实例
全局模式应用级唯一实例,整个应用共享
局部模式页面级实例,互不干扰
双显示方式show(单按钮)和confirm(双按钮)
回调函数支持onConfirm和onCancel回调
高度可定制按钮文字、颜色、样式全部可配置
异步关闭支持loading后手动关闭

pageId实现多实例的原理:

<template>
  <view>
    <u-modal page />
    <u-modal page="deleteConfirm" />
    <u-modal page="loginExpired" />
  </view>
</template>

<script setup>
// 删除操作 - 使用专门的deleteConfirm实例
const deleteModal = useModal({ page: 'deleteConfirm' })
deleteModal.confirm({
  title: '确认删除',
  content: '确定要删除这条数据吗?',
  confirmColor: '#ff4d4f',
  onConfirm: () => {
    deleteItem(id)
  }
})

// 登录过期 - 使用专门的loginExpired实例
const loginModal = useModal({ page: 'loginExpired' })
loginModal.confirm({
  title: '登录已过期',
  content: '请重新登录以继续操作',
  showCancelButton: false,
  confirmText: '重新登录',
  onConfirm: () => {
    uni.reLaunch({ url: '/pages/login/index' })
  }
})
</script>



三、两种全局注入方案

3.1 方案一:使用全局包裹组件(适合新项目)

对于新项目,可以在每个页面中使用app-page组件来包裹内容,从而实现Toast和Modal的全局管理。

创建AppPage.vue:

<template>
  <view class="app-page">
    <slot />
    
    <u-toast page />
    <u-modal page />
  </view>
</template>

在每个页面中使用:

<template>
  <AppPage>
    <view class="content">
      <button @click="handleToast">显示提示</button>
      <button @click="handleModal">显示弹窗</button>
    </view>
  </AppPage>
</template>

<script setup>
import AppPage from '@/components/AppPage.vue'
import { useToast, useModal } from 'uview-pro'

const toast = useToast()
const modal = useModal()

const handleToast = () => {
  toast.show({ title: '全局提示', type: 'success' })
}

const handleModal = () => {
  modal.confirm({
    title: '确认操作?',
    content: '这是一个全局弹窗',
    onConfirm: () => {
      toast.show({ title: '已确认' })
    }
  })
}
</script>

优点:

  • 新项目首选:从一开始就建立良好的架构

  • 完全可控:每个页面的Toast/Modal都受管理

  • 易于维护:统一的页面布局管理模式

3.2 方案二:使用Vite插件(适合老项目,无侵入)

对于现有项目,可以使用@uni-ku/root插件,它可以在不修改任何现有代码的情况下,为应用注入全局根组件。

安装配置:

npm install @uni-ku/root
// vite.config.ts
import { defineConfig } from 'vite'
import Uni from '@dcloudio/vite-plugin-uni'
import UniKuRoot from '@uni-ku/root'

export default defineConfig({
  plugins: [
    UniKuRoot(),
    Uni(),
  ]
})

创建App.ku.vue:

在App.vue同级创建App.ku.vue:

<template>
  <view>
    <KuRootView />
    <u-toast global />
    <u-modal global />
  </view>
</template>

优点:

  • 完全无侵入:不需要修改任何页面代码

  • 即装即用:安装插件即可获得全局能力

  • 适合老项目:不需要重构现有代码



四、实战对比:代码更优雅

4.1 登录表单场景

传统方案(uni.showToast):

const handleLogin = () => {
  uni.showToast({ title: '登录中...', icon: 'loading', duration: 0 })
  
  loginApi(formData).then((res) => {
    uni.hideToast()
    uni.showToast({ title: '登录成功', icon: 'success', duration: 2000 })
    setTimeout(() => uni.navigateTo({ url: '/pages/home' }), 2000)
  }).catch((error) => {
    uni.hideToast()
    uni.showToast({ title: error.message || '登录失败', icon: 'error' })
  })
}

uView Pro方案(useToast):

const toast = useToast()

const handleLogin = () => {
  toast.loading('正在登录中...')

  loginApi(formData).then((res) => {
    toast.success({
      title: '登录成功',
      callback: () => {
        uni.navigateTo({ url: '/pages/home' })
      }
    })
  }).catch((error) => {
    toast.error('登录失败')
  })
}
维度uni.showToastuseToast
代码清晰度⭐⭐⭐⭐⭐⭐⭐⭐
可维护性困难容易
多提示支持

4.2 确认弹窗场景

传统方案(uni.showModal):

const handleDelete = () => {
  uni.showModal({
    title: '确认删除?',
    content: '删除后数据无法恢复',
    success(res) {
      if (res.confirm) {
        deleteApi(id).then(() => {
          uni.showToast({ title: '删除成功' })
        })
      }
    }
  })
}

uView Pro方案(useModal):

const modal = useModal()
const toast = useToast()

const handleDelete = () => {
  modal.confirm({
    title: '确认删除?',
    content: '删除后数据无法恢复',
    onConfirm: () => {
      deleteApi(id).then(() => {
        modal.close()
        toast.success('删除成功')
      })
    },
    onCancel: () => {
      toast.warning('已取消删除')
    }
  })
}
维度uni.showModaluseModal
代码风格回调嵌套函数式调用
灵活性固定样式完全可定制
全局支持

五、项目推荐与总结

5.1 为什么选择uView Pro

特性uni-app官方uView Pro
Toast数量1个无限多个
弹窗风格固定样式完全可定制
代码风格回调嵌套函数式调用
全局支持无根组件支持全局/局部
平台适配需额外处理自动兼容

5.2 集成建议

项目类型推荐方案
新项目app-page全局包裹组件
老项目(不想改代码)@uni-ku/root Vite插件
快速验证直接在页面中使用

5.3 快速开始

如果你正要开始一个uni-app新项目,推荐使用uView Pro Starter,它是一个基于uView Pro UI组件库的快速启动项目。

方式一:直接克隆

git clone https://github.com/anyup/uView-Pro-Starter.git

方式二:使用create-uni脚手架创建

pnpm create uni <项目名称> -t uview-pro-starter

创建完成后安装依赖即可运行项目:

cd uView-Pro-Starter
pnpm install
pnpm run dev

相关资源

  • uView Pro文档:https://uviewpro.cn/

  • uView Pro Starter文档:https://starter.uviewpro.cn/

  • GitHub:https://github.com/anyup/uView-Pro

  • Gitee:https://gitee.com/anyup/uView-Pro


附录:核心API速查

useToast API

// 创建Toast实例
const toast = useToast()                         // 全局模式
const toast = useToast({ page: true })           // 局部模式(当前页面)
const toast = useToast({ page: 'customId' })     // 自定义pageId(多实例)

// 显示Toast
toast.show(content)                               // 基础用法
toast.show({ title, type, position, duration })

// 便捷方法
toast.success(content)
toast.error(content)
toast.warning(content)
toast.info(content)
toast.loading(content)

// 控制
toast.close()                                     // 关闭当前
toast.closeAll()                                  // 关闭所有

useModal API

// 创建Modal实例
const modal = useModal()                          // 全局模式
const modal = useModal({ page: true })            // 局部模式(当前页面)
const modal = useModal({ page: 'deleteModal' })   // 自定义pageId(多实例)

// 显示单按钮弹窗
modal.show(content)
modal.show({ title, content, onConfirm })

// 显示确认弹窗
modal.confirm(content)
modal.confirm({
  title,
  content,
  onConfirm,
  onCancel
})

// 控制
modal.close()
modal.clearLoading()

全局 vs 局部 vs 多实例对比

模式调用方式适用场景
全局模式useToast() / useModal()整个应用共享,适合全局提示
局部模式useToast({ page: true })单个页面独立,不影响其他页面
多实例模式useToast({ page: 'customId' })页面内多个区域,每个区域独立响应

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13553

相关推荐

uni-app关于iOS安全区解决方案

在uniapp开发中,我们可能会遇到一个问题,就是在iOS设备上底部会有一个安全区域,导致页面无法完全显示。因为iphoneX等机型最下面会有条黑色等线,导致按钮等元素被遮住部分,所以设置安全区边距会往上提

uni-app怎样设置横屏?

在使用uni-app开发app应用时候,应用需要横屏显示,那么该如何实现呢?打开pages.json页面,在globalStyle中添加pageOrientation选项

uni-app 微信小程序授权登录

uni.getUserInfo 接口调用方式起初通过button 来获取用户信息,或者 直接调用 uni.getUserInfo 来获取信息 在当前微信更新接口后,这2个接口将直接返回匿名用户数据,不在弹窗提示

uni-app中使用computed计算属性

computed里面的属性不能在data属性中出现,用来监控computed中自定义的变量 ,computed合适多个变量或对象处理后返回一个结果值,其中一个值发生变化则computed监控的属性值就会发生变化

uniapp如何打64位的安装包?

目前安卓在上架一些平台会要求64位,否则导致提交审核不成功,比如提示:请提供64位版本软件包后再提交审核。同时在一些骁龙8Gen3的手机上,也不在兼容32位的应用和游戏了

uniapp如何开启短震动_触感反馈实现

使用 uni-app 开发一款 app,需求中有一项是点击 触感反馈,查阅了 uni-app 相关文档,发现并没有对应的 API,最开始尝试用 震动 的方式来模拟 触感反馈 , 但是感觉效果并不好

uniapp开发注意事项

static 目录下的 js 文件不会被编译,如果里面有 es6 的代码,不经过转换直接运行,在手机设备上会报错。css、less/scss 等资源同样不要放在 static 目录下

uni-app实现苹果内购支付功能

首先我们需要勾选苹果支付,在manifest.json中,选择App模块配置->Payment(支付)。然后打包需要选择打基座包来测试。

uniapp之this作用域

发现了点击按钮1可以更新title内容,但是点击按钮2却无法更新title内容。这个究竟是为什么呢?在changeTitle2方法的success方法中,该success方法指向闭包,所以this属于闭包

uniapp验证码倒计时60s的实现

发送验证码时,不能让客户一直发送验证码,所以需要设置一个60s后才能发送一次;具体代码实现:因为app和其他app不太一样,所以需要选择以这样的方式展示是时间,但是js逻辑代码是一样的;

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!