☰
路线筛选以后详情跳错了,城市探索页别再保存数组下标
2026/10/3 20:08:43 网站建设 项目流程

城市路线列表在只有三条数据时,用下标保存选中项看不出问题。加入距离筛选以后,原本排在第二位的“老城咖啡线”可能变成第一位,详情区域仍读取routes[1],画面便跳到另一条路线。

城市步行探索的页面状态目前用selectedItem: number表示场景列表选择。这个写法适合静态演示,继续加入搜索、距离排序和完成进度后就不够稳定。我把选择状态改成路线 ID,过滤只改变可见集合,不改变用户正在查看的对象。

路线、地标和进度分别建模

路线定义是相对稳定的内容,用户进度会持续变化,两者不应揉进同一个可变数组。

exportinterfaceLandmark{id:stringname:stringorder:numberlatitude:numberlongitude:number}exportinterfaceWalkRoute{id:stringtitle:stringdistanceMeters:numbertags:string[]landmarkIds:string[]}exportinterfaceRouteProgress{routeId:stringvisitedLandmarkIds:string[]startedAt:numberupdatedAt:number}exportinterfaceRouteFilter{keyword:stringmaxDistanceMeters:numbertag:string}

地标坐标属于路线内容;是否到访属于进度。用户重新开始路线时只需要替换RouteProgress,不用复制一遍地标列表。真实定位能力尚未接入时,也可以通过本地按钮模拟到访,验证进度计算和界面刷新。

过滤结果不拥有选中状态

控制器保留完整路线数组和selectedRouteId。搜索结果每次计算,详情则始终回到完整数据中按 ID 查找。

exportclassRouteExplorerController{privateroutes:WalkRoute[]=[]privatefilter:RouteFilter={keyword:'',maxDistanceMeters:10000,tag:''}privateselectedRouteId:string=''setRoutes(routes:WalkRoute[]):void{this.routes=routes.slice()if(!this.routes.some((item:WalkRoute)=>item.id===this.selectedRouteId)){this.selectedRouteId=this.routes.length>0?this.routes[0].id:''}}updateFilter(next:RouteFilter):void{this.filter={...next}}visibleRoutes():WalkRoute[]{constkeyword=this.filter.keyword.trim().toLocaleLowerCase()returnthis.routes.filter((route:WalkRoute)=>{constmatchKeyword=keyword.length===0||route.title.toLocaleLowerCase().includes(keyword)constmatchDistance=route.distanceMeters<=this.filter.maxDistanceMetersconstmatchTag=this.filter.tag.length===0||route.tags.includes(this.filter.tag)returnmatchKeyword&&matchDistance&&matchTag})}selectRoute(routeId:string):boolean{if(!this.routes.some((item:WalkRoute)=>item.id===routeId)){returnfalse}this.selectedRouteId=routeIdreturntrue}selectedRoute():WalkRoute|undefined{returnthis.routes.find((item:WalkRoute)=>item.id===this.selectedRouteId)}}

筛选后选中路线可能暂时不可见。我没有立即把它改成结果第一项,因为用户清除筛选时通常希望回到刚才的路线。页面可以显示“当前路线不在筛选结果中”,由用户明确选择其他路线。

ArkUI 列表键也使用路线 ID

ForEach若用数组下标做键,排序后组件实例可能被复用到另一条数据。路线卡片使用route.id,高亮条件也比较 ID。

@BuilderrouteList(routes:WalkRoute[]){Column({space:12}){ForEach(routes,(route:WalkRoute)=>{Row({space:14}){Column({space:5}){Text(route.title).fontSize(17).fontWeight(FontWeight.Bold)Text(`${(route.distanceMeters/1000).toFixed(1)}km ·`+`${route.landmarkIds.length}个地标`).fontSize(12)}.layoutWeight(1).alignItems(HorizontalAlign.Start)Text(route.tags[0]??'城市漫步').fontSize(12)}.padding(16).backgroundColor(this.selectedRouteId===route.id?'#2AFFFFFF':'#102536').border({width:this.selectedRouteId===route.id?1:0,color:'#4DB9FF'}).borderRadius(20).onClick(()=>{this.selectedRouteId=route.id})},(route:WalkRoute)=>route.id)}}

页面原有“滨江艺术线 2.4 km”“老城咖啡线 1.8 km”“夜景天桥线 3.1 km”都可以转换成WalkRoute。当按距离排序时,只是传给routeList的顺序发生改变,选中的 ID 不变。

地标到访需要幂等

定位回调可能连续命中同一地标。如果每次都向数组追加 ID,页面会显示超过 100% 的完成度。更新进度前先判断是否已经存在。

exportfunctionmarkVisited(progress:RouteProgress,landmarkId:string,now:number):RouteProgress{if(progress.visitedLandmarkIds.includes(landmarkId)){returnprogress}return{...progress,visitedLandmarkIds:[...progress.visitedLandmarkIds,landmarkId],updatedAt:now}}exportfunctioncompletion(route:WalkRoute,progress?:RouteProgress):number{if(!progress||route.landmarkIds.length===0){return0}constvalidVisited=newSet(progress.visitedLandmarkIds.filter((id:string)=>route.landmarkIds.includes(id)))returnMath.round(validVisited.size/route.landmarkIds.length*100)}

完成度只统计仍属于当前路线的地标。路线内容更新、删除某个地标后,旧进度不会把比例撑高。这里使用经纬度只是为了说明数据边界,并没有声称已完成真机定位验证。

页面重建时恢复的是 ID

应用进入后台或窗口重建时,需要保存筛选条件、选中路线 ID 和路线进度。保存下标没有意义,因为下次启动的路线排序可能已经变化。

exportinterfaceExplorerSnapshot{selectedRouteId:stringfilter:RouteFilter progressList:RouteProgress[]savedAt:number}exportfunctionrestoreSelection(snapshot:ExplorerSnapshot,routes:WalkRoute[]):string{if(routes.some((route:WalkRoute)=>route.id===snapshot.selectedRouteId)){returnsnapshot.selectedRouteId}returnroutes.length>0?routes[0].id:''}

页面的蓝色主题、三条路线和顶部标签切换保留原来的视觉结构,数据层改为使用稳定 ID。下一步接入本地路线存储,再由定位适配器上报地标到访事件。无论搜索、排序还是窗口重建,详情都能继续指向用户真正选中的路线。

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

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

立即咨询