平板或折叠屏展开,左侧列表右侧详情看起来很美。用户点进详情,再点返回,应用直接退到桌面。你查返回键监听,没发现问题;查页面栈深度,发现 router 的栈里只有一层,详情页压根没进去过。

根因通常只有一句话:应用还在用 router.pushUrl 管列表-详情,而平行视界只接管 NavPathStack 的路由栈。系统眼里,右栏详情不是一个新页面,而是同一个 Navigation 容器里的详情区域。你用 router 压了一个页面,系统不认,返回键交给系统处理时,它按“应用根页面”的逻辑直接退出了。

Split 和 Stack 是同一个 Navigation 的两种呈现

正确的结构是把列表和详情收进同一个 Navigation,通过 mode 在 NavigationMode.Split 和 NavigationMode.Stack 之间切换。宽窗口时详情落在右栏,窄窗口时详情覆盖全屏。返回一律走 navPathStack.pop(),不要调 router.back()。

typescript

Navigation(this.stack) {
  this.buildList()
}
.navDestination(this.buildDetail)
.mode(this.isSplit() ? NavigationMode.Split : NavigationMode.Stack)

private isSplit(): boolean {
  return this.windowWidth >= 840
}

isSplit() 用窗口宽度判断,不要用设备型号。平行视界把应用压到半屏时,物理屏幕没变,窗口宽度已经掉到 840vp 以下,按型号判断会把单栏场景当成双栏渲染。

详情反复点,导航栈会悄悄变厚

用户从列表点 A,右栏出 A;再点 B,右栏出 B;再点 C。如果每次都用 pushPath,栈里会攒下 A、B、C 三层详情。用户按一次返回,回到 B,再按一次回到 A,和“右栏只承载当前选中详情”的产品预期完全不符。

pushPath 的第二个参数可以指定 LaunchMode,用单例模式避免同名页面重复入栈;如果业务语义是“替换当前详情”而不是“叠一层”,直接用 replacePath 更准确。

typescript

this.stack.replacePath({
  name: 'CatalogDetail',
  param: { sku: nextSku }
})

replacePath 不会给用户“返回上一件商品”的历史,这正是平行视界右栏详情该有的行为。列表的选中态和右栏的路由历史是两件事,不要让点击次数变成栈深度。

冷启动从通知深链进来时,还要处理窗口未就绪的问题。Want 到达时 NavPathStack 可能还没绑定,宽度也没稳定。把“收到意图”和“消费意图”分开,栈就绪后再用 routeKey 查一次是否已经存在同一详情,存在就 moveToTop,不存在才 pushPath,能同时消掉“详情落到左栏”和“右栏叠两张”两个症状。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐