引言路由系统是应用中页面导航的核心。本文将介绍如何设计和封装一个完整的路由系统包括路由配置管理导航守卫参数传递路由拦截通过本文你将掌握如何构建一个健壮的路由系统。学习目标完成本文后你将能够✅ 设计路由配置✅ 实现导航守卫✅ 处理路由参数✅ 添加路由拦截需求分析功能模块设计模块功能描述技术要点路由配置管理路由表路由映射、路径配置导航守卫路由跳转前后处理权限验证、登录检查参数传递页面间数据传递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{constroutePathroute.path;// 处理动态路由if(routePath.includes(:)){constregexnewRegExp(^routePath.replace(/:(\w)/g,([^/]))$);returnregex.test(path);}returnroutePathpath;});}/** * 根据名称获取路由配置 */exportfunctiongetRouteByName(name:string):RouteConfig|undefined{returnroutes.find(routeroute.namename);}/** * 解析动态路由参数 */exportfunctionparseRouteParams(path:string,routePath:string):Recordstring,string{constparams:Recordstring,string{};constpathSegmentspath.split(/).filter(Boolean);constrouteSegmentsroutePath.split(/).filter(Boolean);routeSegments.forEach((segment,index){if(segment.startsWith(:)){constparamNamesegment.slice(1);params[paramName]pathSegments[index]||;}});returnparams;}设计要点:路由表配置动态路由支持参数解析步骤2: 路由工具类封装// router/RouterService.etsimportrouterfromohos.router;importpromptfromohos.prompt;import{routes,getRouteByPath,parseRouteParams,RouteConfig}from./RouterConfig;/** * 路由服务 */classRouterService{privatestaticinstance:RouterService;// 路由栈privaterouteStack:string[][];/** * 获取单例实例 */staticgetInstance():RouterService{if(!RouterService.instance){RouterService.instancenewRouterService();}returnRouterService.instance;}/** * 导航到指定页面 */asyncpush(route:string|RouteConfig,params?:Recordstring,any):Promisevoid{letpath:string;letrouteConfig:RouteConfig|undefined;if(typeofroutestring){// 如果是字符串可能是路径或名称routeConfiggetRouteByPath(route)||getRouteByName(route);pathrouteConfig?.path||route;}else{pathroute.path;routeConfigroute;}// 导航守卫检查constcanNavigateawaitthis.beforeEach(path,routeConfig);if(!canNavigate){return;}try{// 构建URLleturlpages/${routeConfig?.component.split(/)[1]};// 处理动态路由参数if(routeConfig?.path.includes(:)params){letdynamicPathrouteConfig.path;Object.keys(params).forEach(key{dynamicPathdynamicPath.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):Promisevoid{try{awaitrouter.back(options);this.routeStack.pop();}catch(error){console.error(返回失败:,error);}}/** * 返回到指定页面 */asyncbackTo(path:string):Promisevoid{constindexthis.routeStack.indexOf(path);if(index!-1){conststepsthis.routeStack.length-index-1;for(leti0;isteps;i){awaitrouter.back();}this.routeStackthis.routeStack.slice(0,index1);}}/** * 替换当前页面 */asyncreplace(route:string|RouteConfig,params?:Recordstring,any):Promisevoid{leturl:string;if(typeofroutestring){constrouteConfiggetRouteByPath(route)||getRouteByName(route);urlpages/${routeConfig?.component.split(/)[1]};}else{urlpages/${route.component.split(/)[1]};}try{awaitrouter.replaceUrl({url,params:params||{}});}catch(error){console.error(路由替换失败:,error);}}/** * 返回到首页 */asyncbackToHome():Promisevoid{awaitrouter.back({url:pages/Home});this.routeStack[/home];}/** * 导航前守卫 */privateasyncbeforeEach(path:string,routeConfig?:RouteConfig):Promiseboolean{// 检查是否需要登录if(routeConfig?.meta?.requiresAuth){constisLoggedInawaitthis.checkLogin();if(!isLoggedIn){prompt.showToast({message:请先登录});awaitrouter.pushUrl({url:pages/Login});returnfalse;}}// 检查权限if(routeConfig?.meta?.requiresAuth){consthasPermissionawaitthis.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():Promiseboolean{// 从全局状态或本地存储检查登录状态consttokenawaitthis.getToken();return!!token;}/** * 检查权限 */privateasynccheckPermission(path:string):Promiseboolean{// 权限检查逻辑returntrue;}/** * 获取Token */privateasyncgetToken():Promisestring|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?:Recordstring,any;}/** * 全局路由服务实例 */exportconstrouterServiceRouterService.getInstance();/** * 便捷导航方法 */exportconstnavigateTo(route:string,params?:Recordstring,any){returnrouterService.push(route,params);};exportconstnavigateBack(options?:RouterBackOptions){returnrouterService.back(options);};exportconstnavigateReplace(route:string,params?:Recordstring,any){returnrouterService.replace(route,params);};设计要点:统一导航方法导航守卫路由栈管理步骤3: 在组件中使用路由// 在组件中使用路由服务import{routerService,navigateTo}from../router/RouterService;EntryComponentstruct 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仓库应用下载: 华为应用市场
HarmonyOS应用<节气通>开发第27篇:路由系统设计与封装
引言路由系统是应用中页面导航的核心。本文将介绍如何设计和封装一个完整的路由系统包括路由配置管理导航守卫参数传递路由拦截通过本文你将掌握如何构建一个健壮的路由系统。学习目标完成本文后你将能够✅ 设计路由配置✅ 实现导航守卫✅ 处理路由参数✅ 添加路由拦截需求分析功能模块设计模块功能描述技术要点路由配置管理路由表路由映射、路径配置导航守卫路由跳转前后处理权限验证、登录检查参数传递页面间数据传递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{constroutePathroute.path;// 处理动态路由if(routePath.includes(:)){constregexnewRegExp(^routePath.replace(/:(\w)/g,([^/]))$);returnregex.test(path);}returnroutePathpath;});}/** * 根据名称获取路由配置 */exportfunctiongetRouteByName(name:string):RouteConfig|undefined{returnroutes.find(routeroute.namename);}/** * 解析动态路由参数 */exportfunctionparseRouteParams(path:string,routePath:string):Recordstring,string{constparams:Recordstring,string{};constpathSegmentspath.split(/).filter(Boolean);constrouteSegmentsroutePath.split(/).filter(Boolean);routeSegments.forEach((segment,index){if(segment.startsWith(:)){constparamNamesegment.slice(1);params[paramName]pathSegments[index]||;}});returnparams;}设计要点:路由表配置动态路由支持参数解析步骤2: 路由工具类封装// router/RouterService.etsimportrouterfromohos.router;importpromptfromohos.prompt;import{routes,getRouteByPath,parseRouteParams,RouteConfig}from./RouterConfig;/** * 路由服务 */classRouterService{privatestaticinstance:RouterService;// 路由栈privaterouteStack:string[][];/** * 获取单例实例 */staticgetInstance():RouterService{if(!RouterService.instance){RouterService.instancenewRouterService();}returnRouterService.instance;}/** * 导航到指定页面 */asyncpush(route:string|RouteConfig,params?:Recordstring,any):Promisevoid{letpath:string;letrouteConfig:RouteConfig|undefined;if(typeofroutestring){// 如果是字符串可能是路径或名称routeConfiggetRouteByPath(route)||getRouteByName(route);pathrouteConfig?.path||route;}else{pathroute.path;routeConfigroute;}// 导航守卫检查constcanNavigateawaitthis.beforeEach(path,routeConfig);if(!canNavigate){return;}try{// 构建URLleturlpages/${routeConfig?.component.split(/)[1]};// 处理动态路由参数if(routeConfig?.path.includes(:)params){letdynamicPathrouteConfig.path;Object.keys(params).forEach(key{dynamicPathdynamicPath.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):Promisevoid{try{awaitrouter.back(options);this.routeStack.pop();}catch(error){console.error(返回失败:,error);}}/** * 返回到指定页面 */asyncbackTo(path:string):Promisevoid{constindexthis.routeStack.indexOf(path);if(index!-1){conststepsthis.routeStack.length-index-1;for(leti0;isteps;i){awaitrouter.back();}this.routeStackthis.routeStack.slice(0,index1);}}/** * 替换当前页面 */asyncreplace(route:string|RouteConfig,params?:Recordstring,any):Promisevoid{leturl:string;if(typeofroutestring){constrouteConfiggetRouteByPath(route)||getRouteByName(route);urlpages/${routeConfig?.component.split(/)[1]};}else{urlpages/${route.component.split(/)[1]};}try{awaitrouter.replaceUrl({url,params:params||{}});}catch(error){console.error(路由替换失败:,error);}}/** * 返回到首页 */asyncbackToHome():Promisevoid{awaitrouter.back({url:pages/Home});this.routeStack[/home];}/** * 导航前守卫 */privateasyncbeforeEach(path:string,routeConfig?:RouteConfig):Promiseboolean{// 检查是否需要登录if(routeConfig?.meta?.requiresAuth){constisLoggedInawaitthis.checkLogin();if(!isLoggedIn){prompt.showToast({message:请先登录});awaitrouter.pushUrl({url:pages/Login});returnfalse;}}// 检查权限if(routeConfig?.meta?.requiresAuth){consthasPermissionawaitthis.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():Promiseboolean{// 从全局状态或本地存储检查登录状态consttokenawaitthis.getToken();return!!token;}/** * 检查权限 */privateasynccheckPermission(path:string):Promiseboolean{// 权限检查逻辑returntrue;}/** * 获取Token */privateasyncgetToken():Promisestring|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?:Recordstring,any;}/** * 全局路由服务实例 */exportconstrouterServiceRouterService.getInstance();/** * 便捷导航方法 */exportconstnavigateTo(route:string,params?:Recordstring,any){returnrouterService.push(route,params);};exportconstnavigateBack(options?:RouterBackOptions){returnrouterService.back(options);};exportconstnavigateReplace(route:string,params?:Recordstring,any){returnrouterService.replace(route,params);};设计要点:统一导航方法导航守卫路由栈管理步骤3: 在组件中使用路由// 在组件中使用路由服务import{routerService,navigateTo}from../router/RouterService;EntryComponentstruct 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仓库应用下载: 华为应用市场