页面跳转带数据这谁不会pushPath的时候把参数传过去就完了。但现实远没这么简单——传个字符串没问题传个对象呢传个Date呢传个100KB的JSON呢跨Ability跳转呢返回时怎么带数据回来每个问题踩一遍你就知道传参这两个字背后有多少坑。Navigation参数传递NavPathStack的pushPath支持param参数this.navPathStack.pushPath({name:DetailPage,param:{id:42,title:测试文章}});目标页面通过onGetParam回调接收BuilderDetailPage(){NavDestination(){DetailContent()}.onGetParam((param:Object){letpparamasRecordstring,Object;this.itemIdp[id]asnumber;this.itemTitlep[title]asstring;})}关键param的类型是Object需要手动转换。ArkTS不支持泛型参数所以pushPath时传入的param在接收端是Object类型必须用as转换或逐字段取值。参数类型限制Navigation的param参数只支持可序列化类型。这意味着类型能传吗说明number/string/boolean能基本类型没问题普通对象(Record)能字段都是基本类型数组能元素是基本类型Date不能反序列化后变成stringMap/Set不能序列化后丢失类型函数/回调不能不可序列化class实例看情况只有序列化友好的字段能保留Date是高频踩坑点。你以为传了个Date对象过去收到一打开发现是个ISO字符串。解决方式是传时间戳// 发送端this.navPathStack.pushPath({name:SchedulePage,param:{timestamp:Date.now()}});// 接收端lettimestampp[timestamp]asnumber;letdatenewDate(timestamp);复杂对象传递对象嵌套对象时序列化会展平类型信息interfaceAddress{city:string;street:string;}interfaceUser{name:string;age:number;address:Address;}// 传参letuser:User{name:张三,age:25,address:{city:北京,street:中关村}};this.navPathStack.pushPath({name:UserDetail,param:user});// 接收端——address的类型信息丢失了.onGetParam((param:Object){letpparamasRecordstring,Object;letnamep[name]asstring;letaddressObjp[address]asRecordstring,Object;letcityaddressObj[city]asstring;})嵌套层级越深类型转换越痛苦。实际项目中建议只传ID到目标页面再查数据// 只传IDthis.navPathStack.pushPath({name:UserDetail,param:{userId:user.id}});// 目标页面用ID查完整数据.onGetParam(async(param:Object){letpparamasRecordstring,Object;letuserIdp[userId]asnumber;this.userawaitthis.userService.getById(userId);})只传ID的好处数据永远是新鲜的不会因为传了旧数据而显示过期内容参数体积小不需要序列化复杂对象。返回值传递NavPathStack支持pop带返回值// 详情页返回时带数据this.navPathStack.pop({updated:true,itemId:42});// 上一个页面接收this.navPathStack.pushPath({name:DetailPage,param:{id:42}}).then((result:Object){letrresultasRecordstring,Object;letupdatedr[updated]asboolean;if(updated){this.refreshList();}});注意不是所有pushPath都支持then接收返回值。只有当目标页面用pop(Object)返回时then才会触发。如果用户点系统返回键或者手势返回pop没带参数then就不会触发。更可靠的方式是监听navPathStack的变化aboutToAppear():void{this.navPathStack.on(pop,(info:PopInfo){if(info.param!undefined){letresultinfo.paramasRecordstring,Object;letupdatedresult[updated]asboolean;if(updated){this.refreshList();}}});}on(‘pop’)在每次栈弹出时都会触发不管是代码pop还是手势返回。比then更可靠。大数据传递参数体积过大超过100KB时Navigation的序列化会有性能问题。几个解决方案全局状态把数据放到AppStorage或PersistentStorage只传key// 写入全局状态AppStorage.setOrCreate(draftArticle,article);// 只传标记this.navPathStack.pushPath({name:Preview,param:{from:draft}});// 目标页读取letarticleAppStorage.getArticle(draftArticle);文件中转数据写临时文件传文件路径import{fileIo}fromkit.CoreFileKit;// 写入临时文件lettempPaththis.context.tempDir/transfer_data.json;fileIo.writeTextSync(tempPath,JSON.stringify(largeData));this.navPathStack.pushPath({name:Target,param:{filePath:tempPath}});// 目标页读取letcontentfileIo.readTextSync(filePath);单例管理器用内存中的单例持有数据classDataTransferManager{privatestaticinstance:DataTransferManager;privatecache:Mapstring,ObjectnewMap();staticgetInstance():DataTransferManager{if(!DataTransferManager.instance){DataTransferManager.instancenewDataTransferManager();}returnDataTransferManager.instance;}put(key:string,data:Object):void{this.cache.set(key,data);}get(key:string):Object|undefined{returnthis.cache.get(key);}remove(key:string):void{this.cache.delete(key);}}// 使用lettransferKeydata_Date.now().toString();DataTransferManager.getInstance().put(transferKey,largeData);this.navPathStack.pushPath({name:Target,param:{transferKey:transferKey}});// 目标页letdataDataTransferManager.getInstance().get(transferKey);DataTransferManager.getInstance().remove(transferKey);单例方式最简单但要记得用完删除否则内存泄漏。跨Ability传递跨Ability跳转用want传参import{common,Want}fromkit.AbilityKit;letwant:Want{bundleName:com.example.app,abilityName:SecondAbility,parameters:{userId:42,userName:张三}};this.context.startAbility(want);目标Ability在onCreate/onWindowStageCreate中获取参数onCreate(want:Want,launchParam:AbilityConstant.LaunchParam):void{letparamswant.parameters;letuserIdparams[userId]asnumber;}跨Ability的parameters限制更严格——只支持基本类型和简单对象不支持函数、class实例、循环引用对象。这跟Navigation的param限制一样但跨Ability序列化是系统级操作成本更高。参数校验永远不要假设参数一定存在.onGetParam((param:Object){if(paramnull||paramundefined){// 无参数进入显示默认内容this.itemId-1;return;}letpparamasRecordstring,Object;if(p[id]!undefined){this.itemIdp[id]asnumber;}else{this.itemId-1;}})用户可能从深链接、通知、桌面快捷方式进入这些场景可能没有参数。不校验就crash。参数与深链接deepLink进入时参数通过want传递格式是URI// scheme://host/path?keyvalueletwant:Want{uri:myapp://detail?id42fromnotification};// 在Ability中解析leturiwant.uriasstring;leturlnewURL(uri);letidurl.searchParams.get(id);URL解析支持查询参数。但注意URI里的参数都是字符串类型42需要手动parseInt转数字。踩坑清单问题原因解决传Date收到字符串Date被序列化为ISO字符串传时间戳number传class实例丢失方法序列化只保留数据字段只传数据方法在目标页重建返回值then不触发用户手势返回没带参数用on(‘pop’)监听大对象传递卡顿Navigation序列化开销用AppStorage或单例中转跨Ability参数丢失parameters不支持复杂类型只传基本类型或JSON字符串参数undefined导致crash没做空值校验每个字段都判空深链接参数是字符串URI查询参数无类型手动parseInt/parseFloatMap/Set传过去变空不可序列化转成数组再传嵌套对象类型丢失反序列化返回Record只传ID或逐层as转换临时文件没清理tempDir写入后忘记删aboutToDisappear中清理传参的核心原则简单数据用Navigation param复杂数据用全局状态或单例中转跨Ability用want parameters永远只传最小必要信息。传ID不传对象传时间戳不传Date传key不传数据。这不是偷懒是工程素养。