文章导读
- 球员页同时承担“浏览人物信息”和“维护关注状态”两类任务。
- 关注数据通过
@StorageLink('follows')直接驱动,详情页和个人中心都能共享同一份状态。 - 分类过滤既支持中国队,也支持男单、女单、男双、女双、混双等项目维度。
页面效果
球员动态页比普通列表页更容易暴露状态问题。用户点下关注按钮后,既期待当前卡片马上变化,也期待个人中心的关注数量跟着变化;如果两边不一致,这个页面的可信度就会明显下降。
从视觉上看,这页只是一个带分类 Tab 的球员列表;从交互上看,它同时连接了人物卡片、关注状态、个人中心统计和详情跳转,所以非常适合拿来讲响应式状态和列表过滤是如何配合的。
实战拆解
PlayerFeedPage最重要的状态不是selected,而是@StorageLink('follows')。只要关注列表来自 AppStorage,当前页的关注按钮、个人中心的关注数量,以及未来可能加入的“只看已关注球员”能力,看到的就都是同一份数据。相比手动在多个页面里各自维护关注布尔值,这种方式更稳,也更符合 ArkUI 的数据驱动思路。
页面还做了一个很实用的复用设计:通过embedded参数控制标题区域。如果球员页被嵌进底部 Tab,就展示轻量标题行;如果它作为独立页面打开,就走完整NavBar。这样列表内容、过滤逻辑和关注逻辑都能复用,不需要复制出两套页面。
分类过滤部分也值得讲清楚。中国队这个 Tab 使用team === '中国队',其余项目 Tab 则通过稳定的类别值ms、ws、md、wd、xd过滤。文案面向中文读者,逻辑值保持短枚举,这样后续无论调整文案还是扩展国际选手,都不会让过滤规则变得混乱。
关键代码
@Componentexportstruct PlayerFeedPage{embedded:boolean=false;@Stateselected:number=0;@StateisRefreshing:boolean=false;@StorageLink('follows')follows:string[]=[];@StorageProp('remote_players')remotePlayers:Player[]=[];privatetabs:string[]=['全部','中国队','男单','女单','男双','女双','混双'];privatefiltered():Player[]{constsrc:Player[]=this.source();if(this.selected===0){returnsrc;}if(this.selected===1){returnsrc.filter((p:Player)=>p.team==='中国队');}constmap:string[]=['','','ms','ws','md','wd','xd'];constcat:string=map[this.selected];returnsrc.filter((p:Player)=>p.category===cat);}}这段代码把状态来源和过滤规则都限制在了一个清晰边界内。关注状态由 AppStorage 驱动,分类过滤由稳定枚举驱动,页面本身只负责把这两类状态投影成卡片列表。
取舍分析
球员页的核心取舍,在于关注状态应该落在页面局部,还是落在共享状态里。羽球联盟选择后者,是因为关注本身就是跨页面资产,而不是单页交互。只要把它当成共享状态处理,后续接收藏页、个人中心、详情页统计都会轻很多。
另一个取舍是分类维度的组织方式。按国家队和按项目两种分类其实来自不同维度,但它们都被收进同一个 Tab 组里。这样做牺牲了一点语义纯粹性,却换来了更直接的浏览体验。对当前应用规模来说,这种折中是合理的。
设计落点
- 关注状态应共享,不应只停留在单张卡片内部。
- 分类文案可以面向用户,过滤值必须保持稳定且便于扩展。
- 同一业务页通过参数区分嵌入式和独立式展示,能显著减少重复代码。
易踩坑
- 不要让卡片组件直接操作持久化层,关注切换应通过页面或 store 统一处理。
- 不要把分类索引直接当作业务值使用,最好有稳定映射表。
- 列表 key 一定要用球员 id,不能用 index 代替。
验证方式
- 点击球员卡片的关注按钮,确认卡片状态和个人中心关注数一起变化。
- 切换中国队、男单、女单等分类,确认结果与球员数据类别一致。
- 从 Tab 入口和独立页面入口分别打开球员页,确认标题区域符合预期。
参考资料
- ArkUI @StorageLink 装饰器
- ArkUI List 容器
- ArkUI 自定义组件开发
小结
第 15 篇要说明的,不只是一个球员列表怎么过滤,而是共享状态如何让关注行为在多个页面之间保持一致。只要状态来源清晰、过滤规则稳定,这类人物流页面就会非常耐扩展。