03-万少带你精读鸿蒙codelabs——基于List组件实现二级联动效果 
1. 功能介绍 
本案例实现了一个课程分类展示系统,主要包含以下核心功能:
- 双栏联动布局(左侧分类导航栏+右侧课程列表)
- 分类切换时自动滚动到对应课程区域
- 滚动课程列表时自动同步分类选中状态
- 加载状态管理(显示Loading提示)
- 自适应屏幕布局

2. 关键组件 
| 组件/装饰器 | 作用说明 | 
|---|---|
| List | 构建可滚动列表容器(左侧分类列表和右侧课程列表) | 
| ForEach | 循环渲染分类和课程条目 | 
| @State | 管理组件状态(当前选中分类、数据加载状态) | 
| @Builder | 构建可复用的UI片段(列表分组头部) | 
| Scroller | 控制列表滚动行为 | 
| ListItemGroup | 创建带分组的列表项 | 
| StickyStyle.Header | 实现分组头部粘滞效果 | 
3. 逻辑思路 
主要交互流程说明:
- 初始化阶段:通过setTimeout模拟异步数据加载,设置500ms延迟(实际开发中应替换为真实API调用)
- 布局渲染:使用Row容器嵌套两个List实现双栏布局,左侧固定宽度,右侧自适应剩余空间
- 分类联动: - 点击左侧分类时,通过scrollToIndex控制右侧列表滚动
- 滚动右侧列表时,通过onScrollIndex监听首项索引,反向控制左侧分类选中状态
 
- 点击左侧分类时,通过
- 性能优化: - 使用sticky属性实现分组头部粘滞
- 设置scrollBar(BarState.Off)隐藏滚动条
- 通过edgeEffect(EdgeEffect.None)禁用边缘发光效果
 
- 使用
示例图

初始化阶段 
初始化阶段:通过setTimeout模拟异步数据加载,设置500ms延迟(实际开发中应替换为真实API调用)
- currentClassify:当前选中的分类索引。
- requestSuccess:数据加载是否成功的状态标志。
- classifyList:分类数据列表。
- classifyScroller和- scroller:用于控制分类列表和课程列表的滚动。
typescript
@State currentClassify: number = 0; // selected classify index.
@State requestSuccess: boolean = false; // is loading data.
private classifyList: Array<ClassifyModel> = [];
private classifyScroller: Scroller = new Scroller();
private scroller: Scroller = new Scroller();typescript
  aboutToAppear() {
    // loading data.
    setTimeout(() => {
      this.classifyList = ClassifyViewModel.getLinkData();
      this.requestSuccess = true;
    }, Constants.LOADING_DURATION);
  }布局渲染 
- build方法用于构建页面的UI布局。
- 当数据加载成功时,使用List组件渲染分类列表和课程列表。
- classifyList用于渲染分类列表,每个分类项使用- ClassifyItem组件展示。
- classifyList中的每个分类项包含多个课程项,使用- ListItemGroup组件按分类分组展示。
- 当数据加载失败时,显示一个加载中的提示文本。
typescript
build() {
    Row() {
      if (this.requestSuccess) {
        List({ scroller: this.classifyScroller }) {
          ForEach(this.classifyList, (item: ClassifyModel, index?: number) => {
            ListItem() {
              ClassifyItem({
                classifyName: item.classifyName,
                isSelected: this.currentClassify === index,
                onClickAction: () => {
                  if (index !== undefined) {
                    this.classifyChangeAction(index, true);
                  }
                }
              })
            }
          }, (item: ClassifyModel) => item.classifyName.toString() + this.currentClassify)
        }
        .height(Constants.FULL_PERCENT)
        .width($r('app.float.classify_item_width'))
        .backgroundColor($r('app.color.classify_background'))
        .scrollBar(BarState.Off)
        List({ scroller: this.scroller }) {
          ForEach(this.classifyList, (classifyItem: ClassifyModel) => {
            ListItemGroup({
              header: this.ClassifyHeader(classifyItem.classifyName),
              space: Constants.COURSE_ITEM_PADDING
            }) {
              ForEach(classifyItem.courseList, (courseItem: CourseModel) => {
                ListItem() {
                  CourseItem({ itemStr: JSON.stringify(courseItem) })
                }
              }, (courseItem: CourseModel) => `${courseItem.courseId}`)
            }
          }, (item: ClassifyModel) => `${item.classifyId}`)
        }
        .height(Constants.FULL_PERCENT)
        .width(Constants.FULL_PERCENT)
        .padding({ left: $r('app.float.item_padding_left'), right: $r('app.float.course_item_padding') })
        .sticky(StickyStyle.Header)
        .layoutWeight(1)
        .edgeEffect(EdgeEffect.None)
        .onScrollIndex((start: number) => this.classifyChangeAction(start, false))
      } else {
        Text($r('app.string.loading'))
          .fontFamily($r('app.string.hei_ti_medium'))
          .textAlign(TextAlign.Center)
          .height(Constants.FULL_PERCENT)
          .width(Constants.FULL_PERCENT)
      }
    }
    .backgroundColor($r('app.color.base_background'))
  }分类联动 
- 点击左侧分类时,通过scrollToIndex控制右侧列表滚动

- 滚动右侧列表时,通过onScrollIndex监听首项索引,反向控制左侧分类选中状态

性能优化 
- 使用sticky属性实现分组头部粘滞
- 设置scrollBar(BarState.Off)隐藏滚动条
- 通过edgeEffect(EdgeEffect.None)禁用边缘发光效果
总结 
如果你兴趣想要了解更多的开发细节和最新资讯,欢迎在评论区留言或者私信或者看我个人信息,可以加入技术交流群。