swiftUI多 NavigationStack 路由治理实战
·
多 NavigationStack 路由治理实战
引言
当 App 进入多 Tab、多模块阶段后,单一导航栈很容易演变成“跳转难维护、回退不可控”。
更实用的方式是:每个业务域维护独立路径,由全局路由器统一调度。
为什么要做多栈
- 跳转逻辑按业务分治,改动边界更清晰
- 回退链路更可预测
- 登录拦截、权限判断可统一下沉
路由结构示例
import SwiftUI
enum HomeRoute: Hashable {
case detail(id: String)
}
enum ProfileRoute: Hashable {
case settings
}
final class AppRouter: ObservableObject {
@Published var homePath = NavigationPath()
@Published var profilePath = NavigationPath()
func navigateToHome(_ route: HomeRoute) {
homePath.append(route)
}
func navigateToProfile(_ route: ProfileRoute) {
profilePath.append(route)
}
func popHome() {
guard !homePath.isEmpty else { return }
homePath.removeLast()
}
}
视图接入方式
struct HomeRootView: View {
@EnvironmentObject var router: AppRouter
var body: some View {
NavigationStack(path: $router.homePath) {
HomePage()
.navigationDestination(for: HomeRoute.self) { route in
switch route {
case .detail(let id):
DetailPage(id: id)
}
}
}
}
}
扩展点:统一拦截
你可以把登录判断放在 navigate 前置层:
- 未登录:先跳登录页
- 登录成功:恢复目标路由
这样业务页面就不用重复写 if login 判断。
多栈落地路线
第 1 步:先做路由协议,不急着改页面
protocol RouteType: Hashable {}
protocol RouterType: AnyObject {
associatedtype Route: RouteType
var path: NavigationPath { get set }
func push(_ route: Route)
func pop()
}
第 2 步:引入路由解析器(Resolver)
protocol RouteResolver {
associatedtype Route: RouteType
associatedtype Destination: View
@ViewBuilder func resolve(_ route: Route) -> Destination
}
第 3 步:统一跨模块跳转入口
- 业务层不直接访问其他模块的
NavigationPath - 统一通过路由器转发
- 统一处理登录态、权限态
回退链路治理经验
多栈常见 bug 是“页面返回到了错误 Tab”。
解决思路:
- 每个栈的 push/pop 只操作自己的 path
- 跨栈导航先切栈,再 push 目标路由
- 记录来源栈,必要时支持“返回原栈”
实战问答
Q1:多栈会不会很重?
A:比单栈多一点管理成本,但换来可维护性,长期收益更高。
Q2:登录后怎么回到目标页?
A:保存一个 pendingRoute,登录成功后回放。
Q3:路由参数怎么传模型?
A:建议传轻量 ID,详情页自行拉取;大型模型直传会增加耦合与内存风险。
总结
多栈不是“更复杂”,而是把复杂度前置并结构化。
长期看,路由治理越早做,后续维护成本越低。
更多推荐
所有评论(0)