文章目录
- 前言
- 我想实现什么效果
- 问题出在哪
- 为什么 DialogHub 要写死
- 3 种解法
- 解法一:改源码(最直接)
- 解法二:fork 一份,自己维护
- 解法三:绕过 DialogHub,自己封装
- EMBEDDED 和 OVERLAY 到底怎么选
- 写在最后
前言
想用 DialogHub 的 sheet 弹窗做一个"跳页时弹窗随旧页面被覆盖、返回时弹窗还在"的效果,翻了半天找不到mode的入口。打开源码一看,好家伙,直接写死了。
我想实现什么效果
场景很简单:
页面上弹了一个半模态弹窗,用户点了弹窗里的某个按钮,跳转到新页面。这时候我希望弹窗跟着旧页面一起被盖住,而不是浮在所有页面之上。等新页面返回来,弹窗还在原位等着。
这就是SheetMode.EMBEDDED干的事——把弹窗嵌入到页面栈里,跟所属页面共存亡。
官方文档对这个模式的描述很明确:
EMBEDDED 模式下,半模态绑定在所属页面的层级,页面跳转时弹窗随页面一起被覆盖;OVERLAY 模式下,弹窗浮在最上层,不受页面跳转影响。
问题出在哪
DialogHub 是个很好用的弹窗库,封装了很多能力。但问题就出在它的BindSheetExecutor.ets里。
翻到这个文件,第 130 行左右,你会看到这么一行:
sheetOptions.mode=SheetMode.OVERLAY;对,就这么直白。不管你传什么配置,不管你想要什么效果,这里直接把mode覆盖成了OVERLAY。你前面设的值,到这儿就没了。
这就好比你点了一碗清汤面,后厨一律给你加辣——你想不加辣?对不起,没这个选项。
为什么 DialogHub 要写死
坦白讲,这大概率不是有意为难你,而是库作者做了取舍。
OVERLAY是更通用、更安全的默认值。大多数场景下,用户弹窗里做点操作,不想弹窗被页面跳转盖掉,所以浮在最上层反而是符合直觉的。库作者选了"满足 80% 场景"的默认配置,然后——就没留口子给另外 20% 了。
这种事在三方库里挺常见的。封装越高级,灵活性往往越低。
3 种解法
解法一:改源码(最直接)
如果你是通过oh_modules引入的 DialogHub,可以直接改BindSheetExecutor.ets里那行代码:
// 原来:sheetOptions.mode=SheetMode.OVERLAY;// 改成从配置读取,没有就用默认值:sheetOptions.mode=userConfig?.mode??SheetMode.OVERLAY;改完之后,你在调用时就可以传mode: SheetMode.EMBEDDED了。
注意一点:oh_modules里的改动会在ohpm install时被覆盖,所以这个方案只适合本地调试或临时用。
解法二:fork 一份,自己维护
如果你对这个库的依赖比较深,或者团队里有规范要求不直接改oh_modules,最干净的方式是 fork 一份 DialogHub 到自己仓库,把上面那行改掉,再暴露一个mode的配置项出来。
改动量很小,就那一行加一个配置透传,半小时内能搞定。
解法三:绕过 DialogHub,自己封装
如果只有这一个场景需要 EMBEDDED,不值得 fork 整个库,可以直接用官方的bindSheetAPI 自己封装:
@Componentstruct MySheetPage{@StateisShowSheet:boolean=false;build(){Column(){Button('打开弹窗').onClick(()=>{this.isShowSheet=true;})}.bindSheet($$this.isShowSheet,this.sheetBuilder(),{mode:SheetMode.EMBEDDED,// 这里可以直接设置height:400,dragBar:true})}@BuildersheetBuilder(){Column(){Text('我是 EMBEDDED 模式的半模态')Button('跳转新页面').onClick(()=>{// 跳转时弹窗会随当前页面一起被覆盖router.pushUrl({url:'pages/NextPage'})})}.padding(20)}}用官方 API 的好处是完全可控,mode、height、dragBar想怎么配怎么配,不用跟任何三方库的封装限制较劲。
EMBEDDED 和 OVERLAY 到底怎么选
简单总结一下两个模式的适用场景:
用 OVERLAY(弹窗浮在最上层):
- 弹窗是全局性的操作,比如设置、反馈、确认框
- 不希望用户通过页面跳转"逃脱"弹窗
- 弹窗内容与当前页面状态弱相关
用 EMBEDDED(弹窗嵌入页面层级):
- 弹窗是页面内操作的一部分,比如筛选、详情展开
- 允许用户跳转到子页面,弹窗跟着旧页面走
- 弹窗内容与当前页面强绑定,离开页面弹窗就没意义了
你的场景——弹窗里可以跳转到新页面、返回后弹窗还在——就是典型的 EMBEDDED 用法。
写在最后
DialogHub 整体是个不错的库,但这种"写死默认值不留配置口"的问题,确实会给特定场景带来麻烦。如果你也在用这个库碰到了类似限制,改源码或 fork 是最快的路径。
长远来看,希望库作者能把mode作为一个可配置项暴露出来。毕竟,封装是为了更方便,不是为了堵死路。