查看: 399|回复: 3

鸿蒙 uni-app x openDialogPage 弹窗适配避坑

[复制链接]
发表于 5 小时前 | 显示全部楼层 |阅读模式
在鸿蒙平台使用 uni-app x 开发应用时,弹窗是高频交互。过去常见三类方案各有短板:uni.showModal 自定义性差,通常只能改标题和内容文字;前端组件弹窗无法覆盖导航栏和 tabBar,按 back 键还可能把整页关掉;page-container 则要求每个页面都引入组件,写法麻烦。dialogPage 是 uni-app x 提供的弹窗页面方案,鸿蒙 4.61 开始支持。它的核心定位是背景透明页面,挂在主页面之上,不进入页面栈,可以覆盖导航栏和 tabBar,并能拦截 back 键。本文按基础调用、动画、典型场景和踩坑整理。

一、dialogPage 的定位与兼容性
dialogPage 跟普通页面一样,需要在 pages.json 注册,并拥有自己的生命周期。但它不占用页面栈,getCurrentPages() 里拿不到。结构可以理解为:
  1. 主页面(有导航栏和 tabBar)
  2. └── dialogPage 1(透明背景,覆盖全屏)
  3. └── dialogPage 2(可以叠加多个)
复制代码
兼容性上,原文明确鸿蒙 4.61 才支持,之前的版本不能用。适配前先确认鸿蒙版本,避免低版本直接走不通。

二、基础调用:openDialogPage 与 closeDialogPage
打开 dialogPage:
  1. uni.openDialogPage({
  2.   url: '/pages/dialog/my-dialog',
  3.   animationType: 'slide-in-bottom',
  4.   success: () => {
  5.     console.log('打开成功')
  6.   },
  7.   fail: (err) => {
  8.     console.log('打开失败:', err.errMsg)
  9.   }
  10. })
复制代码
关闭:
  1. uni.closeDialogPage({
  2.   animationType: 'slide-out-bottom'
  3. })
复制代码
dialogPage 页面本身按普通 uvue 页面写,但背景透明。实现时有两个关键点:蒙层和内容区域要分开处理点击,蒙层点击关闭,内容区域用 @click.stop 阻止冒泡,避免点内容也关闭;同时用 onBackPress 拦截返回,返回 true 表示拦截默认行为。
  1. const close = () => {
  2.   uni.closeDialogPage()
  3. }
  4. onBackPress(() => {
  5.   close()
  6.   return true // 返回 true 拦截默认行为
  7. })
复制代码
动画方面,openDialogPage 支持多种 animationType。关闭时对应有 slide-out-right、slide-out-left、slide-out-top、slide-out-bottom、fade-out、zoom-in、zoom-fade-in。也可以同时设置 animationDuration,例如:
  1. uni.openDialogPage({
  2.   url: '/pages/dialog/my-dialog',
  3.   animationType: 'slide-in-bottom',
  4.   animationDuration: 300
  5. })
  6. uni.closeDialogPage({
  7.   animationType: 'slide-out-bottom',
  8.   animationDuration: 300
  9. })
复制代码

三、典型实战场景
场景一:底部分享面板。它适合从底部滑出并覆盖 tabBar。布局上 overlay 用 fixed 铺满,justify-content: flex-end 让 panel 贴底;panel 设置顶部圆角;每个分享项点击后调用 close。打开时使用:
  1. uni.openDialogPage({
  2.   url: '/pages/dialog/share-panel',
  3.   animationType: 'slide-in-bottom'
  4. })
复制代码
关闭时可用 slide-out-bottom。这个场景比普通组件弹窗更直接,因为 dialogPage 能覆盖 tabBar。

场景二:确认弹窗。相比 showModal,dialogPage 的自定义空间更大。可以通过 URL 参数把 title、message 传给弹窗页面,在 onLoad 中读取;用户点击取消或确认后关闭页面,并用 uni.$emit 通知主页面结果。主页面通过 uni.$on 监听 confirmResult。
  1. uni.openDialogPage({
  2.   url: '/pages/dialog/confirm-dialog?title=删除确认&message=确定要删除这条记录吗?'
  3. })
  4. uni.$on('confirmResult', (data) => {
  5.   if (data.confirmed) {
  6.     console.log('用户确认了')
  7.   } else {
  8.     console.log('用户取消了')
  9.   }
  10. })
复制代码
弹窗内部取消时发送 { confirmed: false },确认时发送 { confirmed: true }。同时 onBackPress 可以走取消逻辑并返回 true。

场景三:全屏引导页。首次打开 App 时可用 dialogPage 承载全屏引导,内部用 swiper 分页,配合指示点。关闭时使用 fade-out。引导页通常不希望用户按 back 键跳过,因此 onBackPress 直接 return true。
如果打开全屏引导页时需要触发主页面的 onHide,可以在 openDialogPage 中设置 triggerParentHide: true:
  1. uni.openDialogPage({
  2.   url: '/pages/dialog/guide',
  3.   animationType: 'fade-in',
  4.   triggerParentHide: true // 触发主页面的 onHide
  5. })
复制代码
默认情况下,打开 dialogPage 不会触发主页面的 onHide,这个参数适合全屏类弹窗场景。

四、多个 dialogPage 叠加与生命周期
dialogPage 可以叠加多个。在第一个 dialogPage 上再打开第二个:
  1. uni.openDialogPage({
  2.   url: '/pages/dialog/first-dialog'
  3. })
  4. uni.openDialogPage({
  5.   url: '/pages/dialog/second-dialog'
  6. })
复制代码
叠加时,新打开的 dialogPage 会触发前一个的 onHide;关闭时会触发前一个的 onShow。如果需要获取所有 dialogPage,可以通过 UniPage 的 getDialogPages()。

五、与 showModal、page-container 的取舍
从原文结论看,dialogPage 比 showModal 自定义性强,比 page-container 使用方便。它背景透明,能覆盖导航栏和 tabBar;是独立页面,有自己的生命周期;支持多种动画;可以叠加多个;能拦截 back 键;但鸿蒙 4.61 才开始支持。适合底部面板、确认弹窗、引导页、全屏弹窗等场景。

六、踩坑记录
坑一:dialogPage 不进入页面栈。getCurrentPages() 拿不到它。如果需要获取 dialogPage,用 UniPage 的 getDialogPages()。
坑二:在 dialogPage 内获取元素时,uni.getElementById 获取的是栈顶主页面的元素,不是 dialogPage 的。要获取 dialogPage 内元素,需用 this.$page.getElementById() 或 getCurrentInstance()?.proxy?.$page.getElementById()。
  1. this.$page.getElementById()
  2. getCurrentInstance()?.proxy?.$page.getElementById()
复制代码
坑三:在 dialogPage 内调用路由 API。uni.navigateTo 等路由 API 作用于主页面,不是 dialogPage。
坑四:parentPage 默认是当前页面。如果在 app.onLaunch 里调用 openDialogPage,需要指定 parentPage 为首页。
坑五:鸿蒙 4.61 才支持 dialogPage,之前的版本不能用。
坑六:dialogPage 背景透明,蒙层需要自己在页面里实现。如果不加蒙层,用户可以看到底层页面。
坑七:Web 平台 URL 不变。dialogPage 显示时,浏览器 URL 不会变化。这对 SEO 没有影响,但也意味着用户无法通过 URL 直接访问 dialogPage。

总结:dialogPage 把弹窗从普通组件层提升到页面层,因此获得了覆盖导航栏、tabBar 和拦截 back 的能力,但也带来了页面栈、元素获取、路由作用域和版本适配上的差异。在鸿蒙 4.61 及以上版本中,按上述方式使用 openDialogPage、closeDialogPage、onBackPress 和 UniPage.getDialogPages(),可以覆盖分享面板、确认弹窗、全屏引导等常见弹窗需求。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙 uni-app x openDialogPage 弹窗适配避坑

感谢分享,正好最近在鸿蒙端折腾弹窗,这篇避坑整理很实用。dialogPage 不占页面栈、能覆盖导航栏和 tabBar,还能通过 onBackPress 拦截返回,这几点确实解决了普通组件弹窗和 page-container 的不少痛点。基础调用里蒙层和内容区要分开处理点击,内容区用 @click.stop 阻止冒泡,这种细节很容易忽略。确认弹窗用 URL 参数传 title/message,再通过 uni.$emit 和 uni.$on 回传结果,比 showModal 灵活,适合需要自定义按钮和样式的场景。全屏引导页加 triggerParentHide 触发主页面 onHide 也提醒得好,默认不触发这个点之前真没注意。多个 dialogPage 叠加时,新弹窗触发前一个 onHide、关闭触发 onShow,这个生命周期联动也记下了。适配前我会先确认鸿蒙 4.61 版本,再按 animationType 和典型场景逐个试。期待后续“与 show”相关内容补全。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙 uni-app x openDialogPage 弹窗适配避坑

感谢分享,这篇整理很实用。之前在鸿蒙上用 uni-app x 做弹窗,showModal 不够灵活,前端组件又盖不住导航栏和 tabBar,back 键还容易把整页关掉,看完对 dialogPage 的定位清楚多了:透明页面、不占页面栈、能覆盖全屏并拦截返回。基础调用里 openDialogPage 和 closeDialogPage 的动画参数、蒙层与内容区分点击、@click.stop 阻止冒泡、onBackPress 里 close 后 return true,这几处确实容易踩坑。底部分享面板、确认弹窗用 URL 传参加 uni.$emit 和 uni.$on、全屏引导配合 triggerParentHide,这几个场景也很有参考价值。兼容性上鸿蒙 4.61 才支持这个提醒很重要,低版本适配前得先确认。想顺带问下,多个 dialogPage 叠加时关闭是不是后开的先关,以及确认弹窗里主页面监听 uni.$on 后需不需要在合适时机 uni.$off,避免重复触发?期待后续把和 showModal、page-container 的对比也补完。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: 鸿蒙 uni-app x openDialogPage 弹窗适配避坑

感谢分享,鸿蒙上 uni-app x 的弹窗确实坑不少。你这篇把 dialogPage 的定位讲得很清楚:透明页面挂主页面之上、不进页面栈、getCurrentPages 拿不到,但能盖导航栏和 tabBar,还能拦 back,这点对实际项目很有帮助。基础调用和动画参数也很实用,尤其 closeDialogPage 的 animationType 和 animationDuration 对应关系,之前容易写反。蒙层和内容区分开点击、内容用 @click.stop 阻止冒泡,这个细节很关键,不然点内容也把弹窗关了。确认弹窗用 URL 传参加 uni.$emit、uni.$on 回传结果,思路很顺;triggerParentHide 和多个 dialogPage 叠加时触发 onHide、onShow 的说明也记下了。就是看到“五、与 show”好像还没写完,是不是后面还有和 showModal 之类的对比?如果有空可以再补一下低版本鸿蒙的降级方案和兼容性边界,那就更完整了。总之这篇避坑很有用,感谢。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-16 21:13 , Processed in 0.043899 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部