Skip to content

Feat(Fe+HM): add tabbar#223

Merged
dos1in merged 7 commits into
didi:mainfrom
EchoTechFE:feat-tabbar
May 12, 2026
Merged

Feat(Fe+HM): add tabbar#223
dos1in merged 7 commits into
didi:mainfrom
EchoTechFE:feat-tabbar

Conversation

@Hierifer
Copy link
Copy Markdown
Contributor

@Hierifer Hierifer commented May 9, 2026

No description provided.

@dos1in
Copy link
Copy Markdown
Member

dos1in commented May 9, 2026

1. 鸿蒙端非首个 tab 不进入全局栈,导致 currentWebViewId 和生命周期错乱

位置:

  • harmony/dimina/src/main/ets/Container/DMPTabBarContainerView.ets:126
  • harmony/dimina/src/main/ets/DApp/DMPApp.ets:123
  • harmony/dimina/src/main/ets/Navigator/DMPNavigator.ets:307

问题:

非首个 tab 通过 createPageRecordForTab() 创建后,只注册到 webViewIdAndPageRecordMaps,没有进入 global page stack。可是 DMPApp.currentWebViewId 仍然取 navigatorManager.getTopPageRecord()

影响:

当用户切到 tab B 后,从 tab B 调用 navigateToloadSubPackage 或触发生命周期时,框架仍可能认为当前 webView 是栈里的 tab A。比如 DMPNavigator.openPage() 会调用 onHide(this.app.currentWebViewId),实际 hide 的会是旧 tab,新页面的 parentWebViewId 也会挂到旧 tab,导致多 tab 生命周期和后续导航归属错乱。

建议:

需要让当前选中的 tab record 成为导航系统可感知的当前页,或者为 tabbar 场景单独维护 current tab webViewId,并让 currentWebViewId、生命周期、loadSubPackage、navigateTo parent record 都使用这个真实当前 tab。

2. 鸿蒙端 switchTab 无论成功失败都回调 success

位置:

  • harmony/dimina/src/main/ets/Bridges/DMPContainerBridgesModule+Navigator.ets:116
  • harmony/dimina/src/main/ets/Bridges/DMPContainerBridgesModule+Navigator.ets:124
  • harmony/dimina/src/main/ets/Navigator/DMPNavigator.ets:244
  • harmony/dimina/src/main/ets/Navigator/DMPNavigator.ets:281

问题:

桥层 switchTab 调用 navigator.switchTab(routerParam) 后立即 invokeSuccessCallback。但 DMPNavigator.switchTab() 在目标不是 tab 页、栈里找不到 tab 页等失败场景里只是 log 后 return

影响:

JS 侧 wx.switchTab({ fail }) 永远收不到失败。业务会以为已经切到目标 tab,但实际 UI 没变。

建议:

DMPNavigator.switchTab() 返回明确结果,桥层 await 后按结果调用 success 或 fail。失败原因至少应覆盖目标不是 tabBar 页面、当前没有可用 tabBar 容器、eventHub emit 失败等场景。

3. web 端 navigateTo/redirectTo 没有禁止打开 tabBar 页面

位置:

  • fe/packages/container/src/pages/miniApp/miniApp.js:463
  • fe/packages/container/src/pages/miniApp/miniApp.js:521

问题:

web 端 navigateTo 没有在创建 bridge 前拦截 tabBar page,而是会把 tab 页作为普通页面 push 到页面栈里,最后还隐藏 tabbar。

影响:

navigateTo('/tabPage') 会生成一个普通页面版的 tab 页副本,和 tabBarBridges 池中的持久 tab 不是同一个实例。后续再 switchTab 时,页面状态、生命周期、栈行为都可能不符合小程序规范。

建议:

navigateToredirectTo 创建 bridge 前判断 _isTabBarPage(pagePath),如果目标是 tabBar 页面,应走 fail/complete,不应创建页面。tabBar 页面只能通过 switchTab 进入。

4. web 端 tabbar 实际高度和 webviews 底部留白不一致

位置:

  • fe/packages/container/src/pages/miniApp/miniApp.scss:542
  • fe/packages/container/src/pages/miniApp/miniApp.js:904

问题:

tabbar 样式高度是 98px,但显示 tabbar 时 webviewsContainer.style.bottom 只设置为 49px

影响:

页面底部内容会被 tabbar 覆盖约 49px;如果存在底部安全区,覆盖会更明显。

建议:

统一 tabbar 高度和内容区 bottom。可以沿用项目里的 logic(98px) 体系,或者在 JS 中读取实际 tabbar DOM 高度后设置 bottom,避免写死不一致的值。

5. web 端 tabbar 使用 innerHTML 拼接配置,存在 DOM 注入风险

位置:

  • fe/packages/container/src/pages/miniApp/miniApp.js:865

问题:

tabbar 通过 innerHTML 拼接 backgroundColoriconPathselectedIconPathtextpagePath,没有做转义或校验。

影响:

小程序配置中只要出现引号或 HTML 片段,就可能污染宿主 DOM。即使配置来源通常可信,这也是宿主容器层不应该放大的风险。

建议:

改用 document.createElementtextContentsetAttribute 构造 DOM。颜色、资源路径建议做基本校验或白名单处理。

@Hierifer
Copy link
Copy Markdown
Contributor Author

修复了相关问题,增加对 tabbar icon 的 compile,优化了鸿蒙和 Fe 对 icon 的读取,调整了 rem 和 tabbar 在 H5 的展示样式

@dos1in
Copy link
Copy Markdown
Member

dos1in commented May 11, 2026

有三处还需要再看下

1.鸿蒙初始 tab 会重复触发 pageShow
DMPNavigator.openPage() 在 DMPNavigator.ets:345 已经对首个页面发了 onShow,但 DMPTabBarContainerView.aboutToAppear() 又在 DMPTabBarContainerView.ets:120-128 对 initial tab 调了一次 updateTabBarSelection(-1, webViewId),里面会再次 onShow。

2.鸿蒙侧 navigateTo/redirectTo 到 tabBar 页的回调语义还不对
navigateTo 在 DMPNavigator.ets:56-61 拦截后只是 return,但桥层 DMPContainerBridgesModule+Navigator.ets:84-92 仍立即回调 success;redirectTo 桥层 95-104 也仍 success,而且 Navigator 里没看到同等 tabBar 拦截。这两类 case 应该走 fail/complete,不应 success。

3.Web 侧从普通页上方 switchTab 到另一个 tab 时,旧 tab 可能重复 pageHide
navigateTo 时旧 tab 已在 miniApp.js:511-515 hide 过;随后 switchTab 清掉非 tab 页后,如果目标不是当前 tab,又会在 miniApp.js:787-791 对旧 tab 再 pageHide。我看鸿蒙侧已经用 wasPrevTabVisible 处理了这个 case,Web 侧也需要同样判断。

@Hierifer
Copy link
Copy Markdown
Contributor Author

 lint 出现这个问题,ERR_PNPM_NO_LOCKFILE  Cannot install with "frozen-lockfile" because pnpm-lock.yaml is absent 。是增加了新的环节吗

@dos1in
Copy link
Copy Markdown
Member

dos1in commented May 12, 2026

lint 出现这个问题,ERR_PNPM_NO_LOCKFILE  Cannot install with "frozen-lockfile" because pnpm-lock.yaml is absent 。是增加了新的环节吗

不影响,在处理中,以最新 Tests 为准。

@dos1in dos1in merged commit 4e91eaf into didi:main May 12, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants