直接封装 Promise + 全局方法最实用,可避免回调地狱并解决 uni.showModal 在 App/H5/小程序三端渲染逻辑差异导致的样式不一致、参数失效及功能缺失问题。

直接封装成 Promise + 全局方法最实用,避免回调地狱,也绕开 uni.showModal 在 App/H5 上样式不一致的硬伤。
为什么不能直接用 uni.showModal 做全局工具?
它在不同平台渲染逻辑不同:App 端走原生模态框、H5 走 DOM 模拟、小程序是 WebView 层弹层。这意味着你传 confirmColor 或自定义圆角,在 H5 上完全无效;showCancel: false 在某些 Android App 上仍会留出空白按钮位。更麻烦的是,它不支持插槽、不支持富文本、无法加 loading 状态 —— 所有这些都得自己补。
showModal 封装必须处理的三个参数陷阱
实际项目中,90% 的弹窗异常来自参数误传:
-
content为空或undefined时,部分低版本 H5 会直接报错而非静默 fallback -
confirmColor若传了十六进制简写(如#f00),iOS 小程序会忽略,必须用完整格式#ff0000 -
title超过 8 个汉字时,Android App 端可能截断且无省略号,建议提前做title.slice(0, 8) + '...'
推荐封装结构:Promise + 静态方法 + 自动挂载
不要用 Vuex 或全局 event bus 管理弹窗状态,太重。直接返回 Promise,调用处用 await 最干净:
export function showModal(options = {}) {
// 支持字符串快捷调用:showModal('确定要退出登录吗?')
if (typeof options === 'string') {
options = { content: options }
}
const config = {
title: options.title || '提示',
content: options.content || '',
showCancel: options.showCancel !== false,
confirmText: options.confirmText || '确定',
cancelText: options.cancelText || '取消',
confirmColor: options.confirmColor || '#3CC51F',
cancelColor: options.cancelColor || '#999'
}
return new Promise((resolve, reject) => {
uni.showModal({
...config,
success: (res) => {
if (res.confirm) resolve({ confirm: true })
else if (res.cancel) resolve({ confirm: false })
},
fail: reject
})
})
}
// 挂载到 uni 对象(在 main.js 中执行)
uni.$modal = {
alert: (content, title = '提示') => showModal({ content, title, showCancel: false }),
confirm: (content, title = '确认') => showModal({ content, title }),
delete: (content = '确定要删除吗?') => showModal({
content,
title: '删除提示',
confirmText: '删除',
confirmColor: '#DD524D'
})
}
调用时:const res = await uni.$modal.confirm('提交后不可撤回'),比嵌套 success 回调清晰得多。
真正难的是跨端样式统一,不是封装函数
如果你的 UI 设计稿要求弹窗带渐变按钮、图标、阴影、甚至内嵌表单,uni.showModal 就该被彻底弃用。这时候必须手写 custom-modal.vue 组件,用 uni.navigateTo 跳转透明页实现伪全屏弹窗(尤其适合 App/H5),或用 subNVue 做原生级覆盖(仅限 App)。函数封装只是起点,样式和交互自由度才是分水岭 —— 别在 showModal 的参数缝里反复打补丁。










