1# if/else:条件渲染 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @maorh--> 5<!--Designer: @keerecles--> 6<!--Tester: @TerryTsao--> 7<!--Adviser: @zhang_yixin13--> 8 9ArkTS提供了渲染控制能力。条件渲染可根据应用状态,使用if、else和else if渲染相应的UI内容。 10 11> **说明:** 12> 13> 从API version 9开始,该接口支持在ArkTS卡片中使用。 14 15## 使用规则 16 17- 支持if、else和else if语句。 18 19- if和else if后的条件语句可以使用状态变量或常规变量(状态变量的值改变时会实时渲染UI,而常规变量的值改变则不会)。 20 21- 允许在容器组件内使用,通过条件渲染语句构建不同的子组件。 22 23- 条件渲染语句在涉及到组件的父子关系时是“透明”的,父组件和子组件之间的条件渲染语句不影响父组件关于子组件使用的限制。例如,某些容器组件限制子组件的类型或数量。将条件渲染语句用于这些组件内时,这些限制同样适用于条件渲染语句内创建的组件。具体而言,[Grid](../../reference/apis-arkui/arkui-ts/ts-container-grid.md)容器组件的子组件仅支持[GridItem](../../reference/apis-arkui/arkui-ts/ts-container-griditem.md)组件。在Grid内使用条件渲染语句时,条件渲染语句内仅允许使用GridItem组件。 24 25- 每个分支内部的构建函数必须遵循构建函数的规则,并创建一个或多个组件。无法创建组件的空构建函数会产生语法错误。关于构建函数的规则,请参考:[基本语法概述](./arkts-basic-syntax-overview.md)、[声明式UI描述](./arkts-declarative-ui-description.md)。 26 27 28## 更新机制 29 30当if、else if后跟随的状态判断中使用的状态变量值变化时,条件渲染语句会进行更新,更新步骤如下: 31 321. 评估if和else if的状态判断条件,如果分支没有变化,无需执行以下步骤。如果分支有变化,则执行2、3步骤。 33 342. 移除此前构建的所有子组件。 35 363. 执行新分支的构造函数,将生成的子组件添加到if父容器中。如果缺少适用的else分支,则不创建任何内容。 37 38条件可以包含Typescript表达式。构造函数中的表达式不得更改应用程序状态。 39 40## 使用场景 41 42### 使用if进行条件渲染 43 44```ts 45@Entry 46@Component 47struct MyComponent { 48 @State count: number = 0; 49 50 build() { 51 Column() { 52 Text(`count=${this.count}`) 53 54 if (this.count > 0) { 55 Text(`count is positive`) 56 .fontColor(Color.Green) 57 } 58 59 Button('increase count') 60 .onClick(() => { 61 this.count++; 62 }) 63 64 Button('decrease count') 65 .onClick(() => { 66 this.count--; 67 }) 68 } 69 } 70} 71``` 72 73if语句的每个分支都包含一个构建函数。此类构建函数必须创建一个或多个子组件。在初始渲染时,if语句会执行构建函数,并将生成的子组件添加到其父组件中。 74 75每当if或else if条件语句中使用的状态变量发生变化时,条件语句都会更新并重新评估新的条件值。如果条件值评估发生了变化,这意味着需要构建另一个条件分支。此时ArkUI框架将: 76 771. 移除所有以前渲染的(早期分支的)组件。 78 792. 执行新分支的构造函数,将生成的子组件添加到其父组件中。 80 81在以上示例中,当count从0增至1时,if (this.count > 0)更新为true,执行该分支的构造函数,创建一个Text组件并添加到父组件Column中。如果后续count更改为0,则Text组件将从Column组件中删除。由于没有else分支,因此不会执行新的构造函数。 82 83### if ... else ...语句和子组件状态 84 85以下示例包含if ... else ...语句与拥有[\@State](./arkts-state.md)装饰变量的子组件。 86 87```ts 88@Component 89struct CounterView { 90 @State counter: number = 0; 91 label: string = 'unknown'; 92 93 build() { 94 Column({ space: 20 }) { 95 Text(`${this.label}`) 96 Button(`counter ${this.counter} +1`) 97 .onClick(() => { 98 this.counter += 1; 99 }) 100 } 101 .margin(10) 102 .padding(10) 103 .border({ width: 1 }) 104 } 105} 106 107@Entry 108@Component 109struct MainView { 110 @State toggle: boolean = true; 111 112 build() { 113 Column() { 114 if (this.toggle) { 115 CounterView({ label: 'CounterView #positive' }) 116 } else { 117 CounterView({ label: 'CounterView #negative' }) 118 } 119 Button(`toggle ${this.toggle}`) 120 .onClick(() => { 121 this.toggle = !this.toggle; 122 }) 123 } 124 .width('100%') 125 .justifyContent(FlexAlign.Center) 126 } 127} 128``` 129 130**初次渲染**:创建CounterView子组件(label为 'CounterView \#positive'),其状态变量counter初始值为0。 131 132**修改CounterView的counter状态变量**:CounterView子组件(label为 'CounterView \#positive')重新渲染并保留状态变量值。 133 134**修改MainView.toggle状态变量为false**:MainView父组件内的if语句将更新,并进行以下处理: 1351. 删除旧的CounterView子组件(label为 'CounterView \#positive')。 1362. 创建新的CounterView子组件(label为 'CounterView \#negative'),其状态变量counter初始值为0。 137 138> **说明:** 139> 140> CounterView(label为 'CounterView \#positive')和CounterView(label为 'CounterView \#negative')是同一自定义组件的两个不同实例。if分支的更改,不会更新现有子组件,也不会保留状态。 141 142以下示例展示了条件更改时,若需要保留counter值所做的修改。 143 144```ts 145@Component 146struct CounterView { 147 @Link counter: number; 148 label: string = 'unknown'; 149 150 build() { 151 Column({ space: 20 }) { 152 Text(`${this.label}`) 153 .fontSize(20) 154 Button(`counter ${this.counter} +1`) 155 .onClick(() => { 156 this.counter += 1; 157 }) 158 } 159 .margin(10) 160 .padding(10) 161 .border({ width: 1 }) 162 } 163} 164 165@Entry 166@Component 167struct MainView { 168 @State toggle: boolean = true; 169 @State counter: number = 0; 170 171 build() { 172 Column() { 173 if (this.toggle) { 174 CounterView({ counter: $counter, label: 'CounterView #positive' }) 175 } else { 176 CounterView({ counter: $counter, label: 'CounterView #negative' }) 177 } 178 Button(`toggle ${this.toggle}`) 179 .onClick(() => { 180 this.toggle = !this.toggle; 181 }) 182 } 183 .width('100%') 184 .justifyContent(FlexAlign.Center) 185 } 186} 187``` 188 189此处,\@State counter变量归父组件所有。因此,当CounterView组件实例被删除时,该变量不会被销毁。CounterView组件通过[\@Link](./arkts-link.md)装饰器引用状态。状态必须从子级移动到其父级(或父级的父级),以避免在条件内容或重复内容被销毁时丢失状态。 190 191### 嵌套if语句 192 193嵌套条件语句不会影响父组件的相关规则。 194 195```ts 196@Entry 197@Component 198struct MyComponent { 199 @State toggle: boolean = false; 200 @State toggleColor: boolean = false; 201 202 build() { 203 Column({ space: 20 }) { 204 Text('Before') 205 .fontSize(15) 206 if (this.toggle) { 207 Text('Top True, positive 1 top') 208 .backgroundColor('#aaffaa').fontSize(20) 209 // 内部if语句 210 if (this.toggleColor) { 211 Text('Top True, Nested True, positive COLOR Nested ') 212 .backgroundColor('#00aaaa').fontSize(15) 213 } else { 214 Text('Top True, Nested False, Negative COLOR Nested ') 215 .backgroundColor('#aaaaff').fontSize(15) 216 } 217 } else { 218 Text('Top false, negative top level').fontSize(20) 219 .backgroundColor('#ffaaaa') 220 if (this.toggleColor) { 221 Text('positive COLOR Nested ') 222 .backgroundColor('#00aaaa').fontSize(15) 223 } else { 224 Text('Negative COLOR Nested ') 225 .backgroundColor('#aaaaff').fontSize(15) 226 } 227 } 228 Text('After') 229 .fontSize(15) 230 Button('Toggle Outer') 231 .onClick(() => { 232 this.toggle = !this.toggle; 233 }) 234 Button('Toggle Inner') 235 .onClick(() => { 236 this.toggleColor = !this.toggleColor; 237 }) 238 } 239 .width('100%') 240 .justifyContent(FlexAlign.Center) 241 } 242} 243``` 244