HarmonyOS应用<节气通>开发第27篇:路由系统设计与封装
2026/6/13 8:33:53 网站建设 项目流程

引言

路由系统是应用中页面导航的核心。本文将介绍如何设计和封装一个完整的路由系统,包括:

  • 路由配置管理
  • 导航守卫
  • 参数传递
  • 路由拦截

通过本文,你将掌握如何构建一个健壮的路由系统。


学习目标

完成本文后,你将能够:

  • ✅ 设计路由配置
  • ✅ 实现导航守卫
  • ✅ 处理路由参数
  • ✅ 添加路由拦截

需求分析

功能模块设计

模块功能描述技术要点
路由配置管理路由表路由映射、路径配置
导航守卫路由跳转前后处理权限验证、登录检查
参数传递页面间数据传递URL参数、路由参数
路由拦截拦截特定路由登录拦截、权限控制

核心实现

步骤1: 路由配置管理

// router/RouterConfig.ets/** * 路由配置 */exportinterfaceRouteConfig{path:string;name:string;component:string;meta?:RouteMeta;}exportinterfaceRouteMeta{requiresAuth?:boolean;title?:string;keepAlive?:boolean;}/** * 路由表 */exportconstroutes:RouteConfig[]=[// 公共页面{path:'/',name:'Splash',component:'pages/Splash',meta:{keepAlive:false}},{path:'/login',name:'Login',component:'pages/Login',meta:{requiresAuth:false,title:'登录'}},// TabBar页面{path:'/home',name:'Home',component:'pages/Home',meta:{requiresAuth:false,title:'首页'}},{path:'/encyclopedia',name:'Encyclopedia',component:'pages/Encyclopedia',meta:{requiresAuth:false,title:'百科'}},{path:'/quiz',name:'Quiz',component:'pages/Quiz',meta:{requiresAuth:false,title:'测验'}},{path:'/profile',name:'Profile',component:'pages/Profile',meta:{requiresAuth:true,title:'我的'}},// 详情页面{path:'/detail/:id',name:'Detail',component:'pages/Detail',meta:{requiresAuth:false,title:'节气详情'}},{path:'/article/:id',name:'ArticleDetail',component:'pages/ArticleDetail',meta:{requiresAuth:false,title:'文章详情'}},// 设置页面{path:'/settings',name:'Settings',component:'pages/Settings',meta:{requiresAuth:true,title:'设置'}},{path:'/privacy',name:'Privacy',component:'pages/Privacy',meta:{requiresAuth:true,title:'隐私设置'}}];/** * 根据路径获取路由配置 */exportfunctiongetRouteByPath(path:string):RouteConfig|undefined{returnroutes.find(route=>{constroutePath=route.path;// 处理动态路由if(routePath.includes(':')){constregex=newRegExp('^'+routePath.replace(/:(\w+)/g,'([^/]+)')+'$');returnregex.test(path);}returnroutePath===path;});}/** * 根据名称获取路由配置 */exportfunctiongetRouteByName(name:string):RouteConfig|undefined{returnroutes.find(route=>route.name===name);}/** * 解析动态路由参数 */exportfunctionparseRouteParams(path:string,routePath:string):Record<string,string>{constparams:Record<string,string>={};constpathSegments=path.split('/').filter(Boolean);constrouteSegments=routePath.split('/').filter(Boolean);routeSegments.forEach((segment,index)=>{if(segment.startsWith(':')){constparamName=segment.slice(1);params[paramName]=pathSegments[index]||'';}});returnparams;}

设计要点:

  • 路由表配置
  • 动态路由支持
  • 参数解析

步骤2: 路由工具类封装

// router/RouterService.etsimportrouterfrom'@ohos.router';importpromptfrom'@ohos.prompt';import{routes,getRouteByPath,parseRouteParams,RouteConfig}from'./RouterConfig';/** * 路由服务 */classRouterService{privatestaticinstance:RouterService;// 路由栈privaterouteStack:string[]=[];/** * 获取单例实例 */staticgetInstance():RouterService{if(!RouterService.instance){RouterService.instance=newRouterService();}returnRouterService.instance;}/** * 导航到指定页面 */asyncpush(route:string|RouteConfig,params?:Record<string,any>):Promise<void>{letpath:string;letrouteConfig:RouteConfig|undefined;if(typeofroute==='string'){// 如果是字符串,可能是路径或名称routeConfig=getRouteByPath(route)||getRouteByName(route);path=routeConfig?.path||route;}else{path=route.path;routeConfig=route;}// 导航守卫检查constcanNavigate=awaitthis.beforeEach(path,routeConfig);if(!canNavigate){return;}try{// 构建URLleturl=`pages/${routeConfig?.component.split('/')[1]}`;// 处理动态路由参数if(routeConfig?.path.includes(':')&&params){letdynamicPath=routeConfig.path;Object.keys(params).forEach(key=>{dynamicPath=dynamicPath.replace(`:${key}`,params[key]);});}awaitrouter.pushUrl({url,params:params||{}});// 更新路由栈this.routeStack.push(path);// 导航后钩子this.afterEach(path,routeConfig);}catch(error){console.error('路由跳转失败:',error);prompt.showToast({message:'页面跳转失败'});}}/** * 返回上一页 */asyncback(options?:RouterBackOptions):Promise<void>{try{awaitrouter.back(options);this.routeStack.pop();}catch(error){console.error('返回失败:',error);}}/** * 返回到指定页面 */asyncbackTo(path:string):Promise<void>{constindex=this.routeStack.indexOf(path);if(index!==-1){conststeps=this.routeStack.length-index-1;for(leti=0;i<steps;i++){awaitrouter.back();}this.routeStack=this.routeStack.slice(0,index+1);}}/** * 替换当前页面 */asyncreplace(route:string|RouteConfig,params?:Record<string,any>):Promise<void>{leturl:string;if(typeofroute==='string'){constrouteConfig=getRouteByPath(route)||getRouteByName(route);url=`pages/${routeConfig?.component.split('/')[1]}`;}else{url=`pages/${route.component.split('/')[1]}`;}try{awaitrouter.replaceUrl({url,params:params||{}});}catch(error){console.error('路由替换失败:',error);}}/** * 返回到首页 */asyncbackToHome():Promise<void>{awaitrouter.back({url:'pages/Home'});this.routeStack=['/home'];}/** * 导航前守卫 */privateasyncbeforeEach(path:string,routeConfig?:RouteConfig):Promise<boolean>{// 检查是否需要登录if(routeConfig?.meta?.requiresAuth){constisLoggedIn=awaitthis.checkLogin();if(!isLoggedIn){prompt.showToast({message:'请先登录'});awaitrouter.pushUrl({url:'pages/Login'});returnfalse;}}// 检查权限if(routeConfig?.meta?.requiresAuth){consthasPermission=awaitthis.checkPermission(path);if(!hasPermission){prompt.showToast({message:'暂无权限访问'});returnfalse;}}returntrue;}/** * 导航后钩子 */privateafterEach(path:string,routeConfig?:RouteConfig):void{// 设置页面标题if(routeConfig?.meta?.title){this.setTitle(routeConfig.meta.title);}// 发送路由变更事件this.emitRouteChange(path);}/** * 检查登录状态 */privateasynccheckLogin():Promise<boolean>{// 从全局状态或本地存储检查登录状态consttoken=awaitthis.getToken();return!!token;}/** * 检查权限 */privateasynccheckPermission(path:string):Promise<boolean>{// 权限检查逻辑returntrue;}/** * 获取Token */privateasyncgetToken():Promise<string|null>{// 从本地存储获取Tokenreturnnull;}/** * 设置页面标题 */privatesetTitle(title:string):void{// 设置页面标题}/** * 发送路由变更事件 */privateemitRouteChange(path:string):void{// 触发路由变更事件}/** * 获取当前路由 */getCurrentRoute():string|undefined{returnthis.routeStack[this.routeStack.length-1];}/** * 获取路由栈 */getRouteStack():string[]{return[...this.routeStack];}}interfaceRouterBackOptions{url?:string;params?:Record<string,any>;}/** * 全局路由服务实例 */exportconstrouterService=RouterService.getInstance();/** * 便捷导航方法 */exportconstnavigateTo=(route:string,params?:Record<string,any>)=>{returnrouterService.push(route,params);};exportconstnavigateBack=(options?:RouterBackOptions)=>{returnrouterService.back(options);};exportconstnavigateReplace=(route:string,params?:Record<string,any>)=>{returnrouterService.replace(route,params);};

设计要点:

  • 统一导航方法
  • 导航守卫
  • 路由栈管理

步骤3: 在组件中使用路由

// 在组件中使用路由服务import{routerService,navigateTo}from'../router/RouterService';@Entry@Componentstruct HomePage{goToDetail(id:string){// 使用路由服务导航routerService.push('/detail/:id',{id});// 或者使用便捷方法// navigateTo('Detail', { id });}goToLogin(){routerService.push('Login');}goBack(){routerService.back();}build(){Column({space:16}){Button('查看详情').onClick(()=>this.goToDetail('lichun'))Button('去登录').onClick(()=>this.goToLogin())Button('返回').onClick(()=>this.goBack())}.width('100%').height('100%').padding(16).justifyContent(FlexAlign.Center)}}

设计要点:

  • 使用路由服务导航
  • 传递参数
  • 返回上一页

本章小结

核心知识点

本文完成了路由系统的设计与封装:

1. 路由配置

  • 路由表管理
  • 动态路由支持
  • 参数解析

2. 路由服务

  • 统一导航方法
  • 导航守卫
  • 路由栈管理

3. 导航守卫

  • 登录检查
  • 权限验证
  • 导航前后钩子

下一步预告

路由系统已经完成!在下一篇文章中,我们将学习:

  • 工具类封装
  • DateUtils日期工具
  • SeasonUtils季节工具
  • 常用工具函数

相关链接

  • 项目源码: Atomgit仓库
  • 应用下载: 华为应用市场

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询