多级筛选功能实现
========

#### 问题现象

如何实现多级筛选功能？

#### 效果预览

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/80/v3/aPC6ONDrS6quDMDaQFWJkg/zh-cn_image_0000002658844615.png?HW-CC-KV=V1&HW-CC-Date=20260709T134056Z&HW-CC-Expire=86400&HW-CC-Sign=6AC0632D879AEFF723ABE92C407084F566BBB02B9B29CCD0A468044DCAA46AC9 "点击放大")

#### 背景知识

*   [List](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list)列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据，例如图片和文本。
*   [ForEach](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-rendering-control-foreach)接口基于数组循环渲染，需要与容器组件配合使用，且接口返回的组件应当是允许包含在ForEach父容器组件中的子组件。例如，ListItem组件要求ForEach的父容器组件必须为List组件。

#### 解决方案

1.  分别定义一级分类数组arrOne和二级分类数组arrTwo。
2.  使用ForEach对arrOne数组内容进行循环渲染，并添加onClick方法，当点击某一具体元素时，将selectIndexOne的值设置为index索引，将selectIndexTwo的值设置为0。
3.  使用ForEach对arrTwo数组内容进行循环渲染，并添加onClick方法，当点击某一具体元素时，将selectIndexTwo的值设置为index。获得selectIndexOne和selectIndexTwo参数后即可实现多级筛选页面的功能。

完整示例参考如下：

@Entry
@Component
struct MultiLevelFilter {
 _ // 定义一级分类数组，用于显示顶部的分类标题_
  arrOne = \['黑色品种', '有色品种', '农产品', '化工品种', '宏观分析'\];
  _// 定义二级分类数组，每个元素对应一级分类下的子分类_
  arrTwo = \[
    \['焦炭', '玻璃', '螺纹钢', '动力煤', '钢材', '焦煤', '锰硅', '热卷板', '铁矿石', '线材'\],
    \['黄金', '锌', '铝', '铜', '镍', '铅', '锡', '白银', '云南省水电', '工业硅', '碳酸锂'\],
    \['菜籽', '豆粕', '玉米淀粉', '白糖', '苹果', '棉花', '玉米', '豆油', '豆二', '鸡蛋'\],
    \['玻璃', '20号胶', '橡胶', '聚氯乙烯', '聚烯烃', '塑料', '沥青', '甲醇', '尿素', '聚丙烯', '纸浆'\],
    \['中证500指数', '2年期国债', '5年期国债', '上证50指数', '10年期国债', '沪深300指数', '股指'\]
  \];
  _// 用于记录当前选中的一级分类索引_
  @State selectIndexOne: number = 0;
  // 用于记录当前选中的二级分类索引
  @State selectIndexTwo: number = 0;
 _ // 定义两个滚动控制器，用于控制左右两个List的滚动行为_
  filterScroller = new Scroller();
  scroller = new Scroller();

  build() {
    Column() {
    _  // 顶部行布局，包含“筛选”标题和一级分类的水平List_
      Row() {
       _ // 一级分类的水平List_
        List({scroller:this.scroller,space:15}) {
        _  // 使用ForEach对arrOne进行循环渲染_
          ForEach(this.arrOne, (name: string, index) => {
            ListItem() {
              Stack({ alignContent: Alignment.Bottom }) {
              _  // 显示一级分类按钮_
                Button(name)
                  .width(100)
                  .fontColor(this.selectIndexOne === index ? Color.White : Color.Black) _// 根据是否选中设置字体颜色_
                  .height('36vp')
                  .backgroundColor(this.selectIndexOne === index ? '#0A59F7' : '#f1f3f5'); _// 根据是否选中设置背景色_
              }
              .onClick(() => {
              _  // 点击事件：设置选中的一级分类索引，并将二级分类索引重置为0_
                this.selectIndexOne = index;
                this.selectIndexTwo = 0;
                _// 滚动到二级分类的第一个项_
                this.filterScroller.scrollToIndex(0);
              });
            };
          }, (name: string): string => name); _// 用于ForEach key的唯一标识_
        }
        .scrollBar(BarState.Off) _// 隐藏滚动条_
        .listDirection(Axis.Horizontal) _// 设置水平方向滚动_
        .height('40vp');
      }
      .height('40vp')

   _   // 中部行布局，包含“品种”标题和二级分类的水平List_
      Row() {
       _ // 二级分类的水平List，根据selectIndexOne动态显示对应的一级分类下的子分类_
        List({ scroller: this.filterScroller ,space:15}) {
       _   // 使用ForEach对arrTwo中对应一级分类的子分类数组进行循环渲染_
          ForEach(this.arrTwo\[this.selectIndexOne\], (name: string, index) => {
            ListItem() {
              Column() {
                Button(name)
                  .fontColor(this.selectIndexTwo === index ? Color.White : Color.Black)
                  .height('36vp')
                  .backgroundColor(this.selectIndexTwo === index ? '#0A59F7' : '#f1f3f5');
              }
              .onClick(() => {
                this.selectIndexTwo = index;
              });
            };
          }, (name: string): string => name);
        }
        .scrollBar(BarState.Off)
        .listDirection(Axis.Horizontal)
        .height('40vp');
      }
      .height('40vp')
      .margin({ top:'10vp',bottom:'20vp'});
      Row() {
        Text('首页')
          .fontSize(30);
      }
      .height('40vp')
    }
    .padding('20vp')
    .width('100%')
    .height('100%');
  }
}