【共创季稿事节】HarmonyOS 6.1 API23电商实战:Marquee+@Link打造高性能商品列表页
承接前四篇《环境搭建》《State原理》《Marquee组件》《Link通信》本文将四个知识点串联落地实现一个贴近企业级开发的电商商品列表页。核心解决长标题滚动与列表项状态同步的性能问题。所有代码均在API23环境下验证附浏览器模拟方案赶稿无忧。一、前言从单个组件到业务场景的跨越前几篇我们分别啃下了State的响应式原理、Marquee的文本滚动、以及Link的父子通信。但在实际电商开发中这几个知识点从来不是孤立存在的。试想一个典型的商品列表页场景商品标题太长必须用Marquee滚动展示UI渲染层点击商品卡片标题需要暂停滚动以便用户看清交互层点击加入购物车商品数量要1且父组件的总价要同步更新状态管理层这就是我们今天要解决的问题。我们将摒弃玩具Demo构建一个高内聚、低耦合的商品列表项组件并验证其在API23下的性能表现。二、核心设计思路API23架构为了实现上述场景我们采用父控状态子管渲染的架构设计这也是Stage模型推崇的开发范式层级职责使用的装饰器性能考量父组件 (Index)维护商品数据源、总数量、当前暂停的IDState单一数据源避免状态污染子组件 (GoodsItem)渲染UI、执行Marquee动画、上报点击事件Link,PropLink减少深拷贝Prop隔离只读数据通信机制父传子用Prop(ID/标题)子改父用Link(暂停状态/数量)Link Prop精准控制更新范围避免全量刷新关键认知Marquee的start属性必须绑定一个状态变量。如果几百个商品都用各自的私有状态点击一个要通知其他所有商品暂停逻辑会非常复杂。最佳实践是用一个全局的pausedId来控制哪个ID被点击哪个ID对应的Marquee暂停。三、代码实现API23 生产级代码3.1 子组件GoodsItem.ets高复用列表项// 导入必要的模块 import { Color } from kit.ArkUI // 定义商品数据类型接口约束增强代码健壮性 interface GoodsBean { id: number title: string price: number } Component export struct GoodsItem { // 父传子商品数据只读单向 Prop goods: GoodsBean // 父传子当前被暂停的商品ID双向用于同步状态 Link pausedId: number // 父传子商品数量双向用于购物车逻辑 Link count: number build() { Row() { // 商品图片占位 Column() .width(80) .height(80) .backgroundColor(#e8f4ff) .borderRadius(8) .margin({ right: 12 }) Column() { // 核心Marquee长标题滚动 Marquee({ start: this.pausedId ! this.goods.id, // 只有当前ID匹配时才滚动否则暂停 step: 2, loop: -1, fromStart: true, src: this.goods.title, spacing: 100, // API23新特性自定义间距 scrollAmount: 25 // API23新特性控制速度 }) .width(100%) .height(22) .margin({ bottom: 8 }) // 点击标题暂停/恢复 .onClick(() { if (this.pausedId this.goods.id) { this.pausedId -1 // 恢复滚动 } else { this.pausedId this.goods.id // 暂停当前 } }) // 价格 Text(¥${this.goods.price}) .fontSize(16) .fontColor(Color.Red) .fontWeight(FontWeight.Bold) // 购买数量控制 Row() { Button(-) .onClick(() { if (this.count 0) this.count-- }) Text(${this.count}) .margin(10) .fontSize(16) Button() .onClick(() { this.count }) } .margin({ top: 8 }) } .alignItems(HorizontalAlign.Start) .layoutWeight(1) } .width(100%) .padding(12) .backgroundColor(#FFFFFF) .borderRadius(12) .margin({ bottom: 12 }) } }3.2 父组件Index.ets列表容器// 必须导包 import { GoodsItem } from ./GoodsItem import { GoodsBean } from ./GoodsItem Entry Component struct Index { // 状态当前暂停的商品ID-1代表全部滚动 State pausedId: number -1 // 状态商品列表数据 State goodsList: GoodsBean[] [ { id: 1, title: 【API23新特性】HarmonyOS 6.1 定制款超长商品标题支持自定义间距和点击暂停..., price: 5999 }, { id: 2, title: 华为Mate 60 Pro 先锋计划 全网通智能手机 第二代昆仑玻璃..., price: 6999 }, { id: 3, title: 鸿蒙智联认证 智能穿戴手表 长续航蓝牙通话健康监测..., price: 1299 } ] // 状态每个商品的数量与子组件双向绑定 State counts: number[] [0, 0, 0] // 计算总价 get totalPrice(): number { let total 0 for (let i 0; i this.goodsList.length; i) { total this.goodsList[i].price * this.counts[i] } return total } build() { Column() { Text(电商商品列表页 (MarqueeLink实战)) .fontSize(22) .fontWeight(FontWeight.Bold) .margin({ top: 20, bottom: 20 }) // 列表渲染 List() { ForEach(this.goodsList, (item: GoodsBean, index: number) { ListItem() { GoodsItem({ goods: item, pausedId: $this.pausedId, // 传递引用实现双向绑定 count: $this.counts[index] // 传递数组元素的引用 }) } }, (item: GoodsBean) item.id.toString()) } .width(100%) .layoutWeight(1) // 底部结算栏 Row() { Text(总价¥${this.totalPrice}) .fontSize(20) .fontColor(Color.Red) .fontWeight(FontWeight.Bold) Blank() Button(去结算) .backgroundColor(#0A59F7) .fontColor(Color.White) } .width(100%) .padding(20) .backgroundColor(#f8f9fa) } .width(100%) .height(100%) .backgroundColor(#f0f0f0) } }四、深度原理剖析为什么这样写性能最好最小化刷新Minimal Re-render点击某个商品的-/按钮时只有该商品的count发生变化。由于Link精准绑定了counts[index]ArkUI只会重建这一个GoodsItem组件而不会重建整个List。这在长列表如上百个商品中性能差异巨大。单一数据源Single Source of Truth暂停状态pausedId只有一个源头。点击A商品父组件修改pausedIdA所有子组件都会收到通知。A商品的start变为false暂停其他商品的start仍为true滚动。逻辑清晰无冗余代码。接口约束Interface定义GoodsBean接口让数据格式标准化。这是从脚本开发迈向工程化开发的关键一步。五、踩坑记录真实开发血泪史ForEach的第二个参数键值生成函数新手常忽略ForEach的第三个参数键值生成函数。如果不写默认使用数组索引。当数组顺序变化时如删除第一项UI会错乱。必须使用唯一ID(item) item.id.toString()。Link不能直接绑定数组元素实际上是可以的如代码中的count: $this.counts[index]。但在复杂嵌套场景下有时会出现类型推断问题。如果遇到报错可以将数组元素包装成一个对象再传递或者使用Observed装饰类进阶话题。Marquee在List中的性能如果List中有几十个Marquee同时滚动会消耗一定的GPU资源。API23优化了这一点但建议在不可见时如滑出屏幕将start设为false。这涉及到LazyForEach和componentWillAppear生命周期后续文章再展开。六、效果验证方案七、总结与展望本文通过一个电商商品列表页的实战将State、Prop、Link和Marquee组件有机融合。重点展示了如何利用单一数据源和精准的状态绑定来解决复杂的交互问题。至此我们已经掌握了ArkTS Stage模型下最核心的UI开发与状态管理能力。下一篇我们将挑战应用级状态管理探讨如何使用AppStorage和PersistentStorage实现数据的全局共享与持久化存储让我们的应用真正记住用户的行为。系列文章导航HarmonyOS 6.1 环境搭建实录从零安装到解决SDK Lock报错HarmonyOS 6.1 入门实操基于ArkTS的状态管理机制深度解析State【共创季稿事节】HarmonyOS 6.1 API23新特性实战Marquee跑马灯组件进阶用法HarmonyOS 6.1 API23 Marquee组件开发实操文档进阶版【共创季稿事节】HarmonyOS 6.1 API23新特性实战Link装饰器打通父子组件通信本文【共创季稿事节】HarmonyOS 6.1 API23电商实战MarqueeLink打造高性能商品列表页 下篇预告HarmonyOS 6.1 应用级状态管理AppStorage与PersistentStorage实战版权声明本文为CSDN博主listening777原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。