1# 列表的多级联动
2## 场景介绍
3多级联动是指根据一个列表(一级列表)的选择结果,来更新另一个列表(二级列表)的选择项,再来更新第三个列表(三级列表)的选择,以此类推。这种联动可以根据用户的实际需求,快速定位到想要的选项,提高交互体验。例如,省市县三级地区的选择、工作部门的选择,本文即为大家介绍如何开发列表的多级联动。
4
5## 效果呈现
6本例效果图如下:
7![](./figures/sanji.gif)
8
9## 运行环境
10
11本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发:
12- IDE: DevEco Studio 4.0 Release
13- SDK: Ohos_sdk_public 4.0.10.13 (API Version 10 Release)
14
15## 实现思路
16本例关键功能点及其实现思路如下:
17- 文本选择弹窗:通过CompanyDialogController实现。
18
19- 点击公司列表弹出对应旗下子公司的列表,点击子公司列表弹出对应的旗下部门的网格:通过ForEach的嵌套使用进行循环渲染公司列表、子公司列表、部门。
20
21## 开发步骤
22根据实现思路,具体开发步骤如下:
231. 构建列表数据。
24
25    ```ts
26    // LinkageData.ets
27    export interface Link{
28      name:string
29      Subsidiary:a[]
30    }
31    export interface a{
32      name:string,
33    department:Array<string>
34    }
35    export const LinkageData:Link[]=[
36      {
37        name:"A公司",
38        Subsidiary:[
39          {
40            name:"a子公司",
41            department:[
42              "技术部",
43              "工程部",
44              "维护部",
45              "运营部",
46              "售后部"
47            ]
48          },
49          {
50            name:"b子公司",
51            department:[
52              "行政部",
53              "管理部",
54              "服务部",
55              "秘书部"
56            ]
57          },
58          {
59            name:"c子公司",
60            department:[
61              "行动部",
62              "情报部",
63              "信息部"
64            ]
65          }
66        ]
67      },
68    ...
69    ]
70    ```
712. 打开自定义弹窗。通过CustomDialogController以实现自定义弹窗的打开。
72
73    ```ts
74    // Index.ets
75    ...
76    CompanyDialogController:CustomDialogController = new CustomDialogController({
77      builder:CompanyPicker({
78        postA:$postA,
79        company:$companyButtonTitle,
80        companyStringArray:this.CompanyArray
81      }),
82      autoCancel:true,
83      alignment:DialogAlignment.Bottom,
84      customStyle:true
85    })
86
87    build() {
88      Column(){
89        Text(this.companyButtonTitle)
90          .height(50)
91          .fontSize(30)
92          .borderRadius(10)
93          .backgroundColor(0xFFFFFF)
94          .onClick(()=>{
95            this.CompanyDialogController.open();
96          })
97      }.width('100%').height('100%')
98      .backgroundColor(Color.White)
99      .padding({top:5})
100    }
101    ...
102    ```
1033. 具体部门的选择。通过ForEach的嵌套使用循环渲染公司列表、子公司列表、部门。通过点击事件将具体部门展示到弹窗上方,点击确定后,界面显示具体部门。
104
105    ```ts
106    //  Index.ets
107    ...
108    List({space:15, initialIndex:0,scroller:this.scroller}){
109      ForEach(LinkageData,(Item:Link)=>{
110        ListItem() {
111          Column() {
112            Text(`${Item.name === '' ? Item : Item.name}`)
113              .height(40)
114              .fontSize(30)
115              .fontColor('#000000')
116              .width('100%')
117              .margin({ top: 10 })
118              .onClick(() => {
119                if (this.isCompany === Item.name) {
120                  this.isCompany = ''
121                } else {
122                  this.isCompany = Item.name
123                }
124              })
125            if (this.isCompany === Item.name) {
126              List({ space: 10 }) {
127                ForEach(Item.Subsidiary, (ItemA: a) => {
128                  ListItem() {
129                    Column() {
130                      Text(`${Item.name === undefined ? ItemA : ItemA.name}`)
131                        .width('100%')
132                        .height(20)
133                        .fontSize(18)
134                        .margin({ top: 4 })
135                        .onClick(() => {
136                          if (this.isSubsidiaryAA === ItemA.name) {
137                            this.isSubsidiaryAA = ''
138                          } else {
139                            this.isSubsidiaryAA = ItemA.name
140                          }
141                        })
142                        if (this.isSubsidiaryAA === ItemA.name) {
143                          Grid() {
144                            ForEach(ItemA.department, (departmentName: string) => {
145                              GridItem() {
146                                Text(`${departmentName}`)
147                                  .margin({ top: 10, bottom: 10 })
148                                  .fontSize(14)
149                                  .maxLines(5)
150                                  .fontColor(Color.Black)
151                                  .borderRadius(5)
152                                  .padding(5)
153                                  .backgroundColor('#00FFFF')
154                                  .onClick(() => {
155                                    this.tempDepartment = `${Item.name}${ItemA.name}${departmentName}`
156                                  })
157                              }
158                            })
159                          }.width('100%')
160                          .height(100)
161                          .columnsTemplate('1fr 1fr')
162                        }
163                    }
164                  }
165                })
166              }
167            }
168          }
169        }
170      })
171    }
172    ...
173    ```
1744. 自定义弹窗的关闭。
175
176    ```ts
177    // Index.ets
178    ...
179    Row(){
180      Text(this.tempDepartment)
181        .fontSize(14)
182        .fontColor(Color.White)
183        .layoutWeight(1)
184        .height(40)
185      Button("确定",{type:ButtonType.Normal,stateEffect:true})
186        .fontSize(14)
187        .fontColor(Color.White)
188        .layoutWeight(1)
189        .height(40)
190        .onClick(()=>{
191          this.company = this.tempDepartment
192          if (this.controller !== undefined){
193            this.controller.close()
194          }
195        })
196    }
197    ...
198    ```
199## 完整代码
200LinkageData.ets根据效果开发者自行进行编辑,在Index.ets在开发步骤中基本展示全部代码。
201## 参考
202[自定义弹窗](../application-dev/reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md)
203
204[循环渲染](../application-dev/quick-start/arkts-rendering-control-foreach.md)