Yew Router 怎么做参数路由、跳转和权限控制?
Yew 做路由管理,核心是 yew-router 的 Routable 枚举。你把 URL 规则写成 Rust 类型,再用 BrowserRouter 和 Switch 把不同路由映射到组件。它比手写 window.location 安全得多:参数解析、404、导航链接都能在编译期获得一部分保障。真正容易出问题的地方不在“怎么配路由”,而在路由粒度、权限检查、查询参数和浏览器刷新后的状态恢复。
先把路由当成公开接口设计
路由不是组件文件名的翻译,它是用户会收藏、分享、刷新进入的地址。列表页、详情页、设置页可以成为路由;弹窗开关、局部 tab 是否进 URL,要看它有没有独立访问价值。过细的路由会让导航逻辑变复杂,过粗又会让返回按钮不好用。我的经验是:刷新后仍然应该保留的页面状态,才值得放进路径或查询参数。
rustuse yew::prelude::*; use yew_router::prelude::*; #[derive(Clone, Routable, PartialEq)] enum Route { #[at("/")] Home, #[at("/users")] Users, #[at("/users/:id")] UserDetail { id: u32 }, #[at("/login")] Login, #[not_found] #[at("/404")] NotFound, } fn switch(route: Route) -> Html { match route { Route::Home => html! { <Home /> }, Route::Users => html! { <Users /> }, Route::UserDetail { id } => html! { <UserDetail id={id} /> }, Route::Login => html! { <Login /> }, Route::NotFound => html! { <h2>{ "页面不存在" }</h2> }, } } #[function_component(App)] fn app() -> Html { html! { <BrowserRouter><Switch<Route> render={switch} /></BrowserRouter> } }
跳转别只会写 Link
静态导航用 Link<Route>,比如菜单、面包屑、卡片入口。登录成功后跳转、提交表单后回详情页这类动作,需要 use_navigator。边界在于:导航是一种副作用,不要在组件渲染过程中直接触发,否则可能造成重复跳转。通常把跳转放在点击回调、请求成功分支或 effect 里,并且先判断条件是否真的变化。
rust#[function_component(LoginButton)] fn login_button() -> Html { let nav = use_navigator().unwrap(); let onclick = Callback::from(move |_| { // 登录成功后再跳转,示例省略请求逻辑 nav.push(&Route::Users); }); html! { <button {onclick}>{ "进入用户列表" }</button> } }
权限控制要区分“未登录”和“无权限”
很多路由守卫写坏,是因为把所有异常都跳到登录页。未登录应该去登录页,无权限应该显示 403,资源不存在应该是 404。Yew Router 没有强制的守卫语法,常见做法是在 switch 或页面壳组件里根据认证状态返回不同组件。踩坑点是认证状态往往异步加载,刚进页面时既不是已登录也不是未登录,最好先显示 loading,避免页面闪一下就跳走。
查询参数要有默认值和兼容策略
真实项目里的 URL 会被用户收藏,也会被旧版本页面留下来,所以解析查询参数时不要假设它永远合法。分页不是数字、筛选值已经下线、参数组合互相冲突,都应该回退到安全默认值。这里的取舍是不要把所有状态都塞进 URL,只有刷新后需要保留、分享后仍有意义的状态才放进去,否则路由会变成难维护的状态仓库。
对运营活动页还要考虑短链接和历史链接兼容,旧路径最好通过服务端或前端重定向到新路由。这样会多维护一层映射,但比让用户点进收藏夹直接看到 404 更可控。
追问
路由参数应该用 path 还是 query?
资源身份用 path,例如 /users/42,因为它表达的是页面主体。筛选、排序、分页更适合 query,例如 /users?page=2&role=admin,因为它们只是同一资源列表的视图状态。取舍标准是:去掉这个字段后页面主体是否改变,改变就放 path,不改变就放 query。
yew-router 支持嵌套路由吗?
可以做,但通常不是像某些前端框架那样自动生成嵌套出口,而是通过路由枚举和组件组合来表达。后台管理系统可以把 /settings/profile、/settings/billing 定成不同变体,再由 Settings 布局组件包一层。边界是嵌套太深会让枚举变臃肿,这时可以拆分子路由枚举,但别为了“架构好看”过早拆。
刷新页面 404 是 Yew 的问题吗?
多数情况下不是 Yew 的问题,而是服务器没有把未知路径回退到 index.html。开发环境里路由正常,部署到 Nginx 或静态托管后刷新 404,就是典型踩坑。解决方式是在服务器配置 history fallback;如果做不到,就考虑 HashRouter 风格的 URL,但链接观感和 SEO 会差一些。
权限判断放 switch 里还是页面组件里?
简单项目放 switch 里够用,可以集中看清哪些路由需要登录。复杂项目更适合做 ProtectedRoute 或布局组件,因为权限往往还影响菜单、面包屑和页面骨架。取舍是集中判断方便审计,分散到页面更灵活,但要避免同一套权限规则复制三四遍。
路由懒加载在 Yew 里值得做吗?
管理后台、图表页、编辑器页这类包体大的页面值得考虑,普通三五个页面的小应用不一定划算。Rust/Wasm 的拆包和加载链路比 JS 项目更需要构建工具配合,贸然做会增加调试成本。边界是先用构建分析看首包是否真的过大,再决定是否引入懒加载,不要只因为“最佳实践”就上。
小结
Yew Router 的基础 API 很少,难点在 URL 设计和副作用边界。把路由当作产品接口,而不是组件目录索引,再认真处理参数、刷新、权限和跳转时机,路由层就会稳定很多。