第6篇:条件渲染——根据条件显示内容

本课目标:掌握if-else条件渲染,能根据状态显示不同内容
**作者:**中文编程倡导者—— 李金雨
预计课时:2课时(90分钟)
难度等级:⭐⭐⭐(进阶)


一、开篇引入

1.1 生活中的"条件"

生活中处处都有"如果…就…":

  • 如果下雨,就带伞
  • 如果到18岁,就可以考驾照
  • 如果成绩>=60,就及格
  • 如果登录了,就显示用户名

1.2 程序中的条件

应用界面也需要根据条件显示不同内容:

  • 用户登录了 → 显示头像和用户名
  • 用户没登录 → 显示"请登录"按钮
  • 数据加载中 → 显示转圈圈
  • 数据加载完 → 显示内容
  • 列表为空 → 显示"暂无数据"

1.3 本课目标

今天我们要学习:

  1. if-else 条件渲染
  2. 多种条件判断
  3. 条件渲染的常见场景
  4. 实战:登录状态切换、权限控制、加载状态

1.4 预期成果

完成本课后,你能做出这样的应用:

登录状态切换:           加载状态:              权限控制:
┌─────────────┐        ┌─────────────┐        ┌─────────────┐
│             │        │             │        │             │
│  未登录时:  │        │   ⏳        │        │  🔒 VIP专区  │
│             │        │  加载中...   │        │             │
│  [登录按钮]  │        │             │        │  普通用户:  │
│             │        │             │        │  "请先升级   │
│  已登录时:  │        │  加载完成:  │        │   VIP"      │
│             │        │             │        │             │
│  👤 张三    │        │  [内容显示]  │        │  VIP用户:   │
│  退出登录   │        │             │        │  [专属内容]  │
│             │        │             │        │             │
└─────────────┘        └─────────────┘        └─────────────┘

二、概念讲解

2.1 if-else基础

基本语法
if (条件) {
  // 条件为true时显示的内容
} else {
  // 条件为false时显示的内容
}
简单例子
@State 是否登录: boolean = false

build() {
  Column() {
    if (this.是否登录) {
      Text("欢迎回来!")
    } else {
      Text("请先登录")
    }
  }
}

2.2 多种条件判断

if-else if-else

多个条件依次判断:

@State 成绩: number = 85

build() {
  Column() {
    if (this.成绩 >= 90) {
      Text("优秀!")
        .fontColor("#4CAF50")
    } else if (this.成绩 >= 80) {
      Text("良好")
        .fontColor("#2196F3")
    } else if (this.成绩 >= 60) {
      Text("及格")
        .fontColor("#FF9800")
    } else {
      Text("不及格")
        .fontColor("#F44336")
    }
  }
}
嵌套if

条件里面还有条件:

if (this.是否登录) {
  if (this.是否是VIP) {
    Text("欢迎VIP用户!")
  } else {
    Text("欢迎普通用户")
  }
} else {
  Text("请先登录")
}

2.3 条件运算符

三元运算符(简单条件)
// 语法:条件 ? 真时的值 : 假时的值

Text(this.是否登录 ? "已登录" : "未登录")

// 等同于:
if (this.是否登录) {
  Text("已登录")
} else {
  Text("未登录")
}
逻辑运算符
// &&(并且)- 两个条件都满足
if (this.是否登录 && this.是否是VIP) {
  Text("VIP会员")
}

// ||(或者)- 满足其中一个
if (this.是管理员 || this.是版主) {
  Text("有管理权限")
}

// !(非)- 取反
if (!this.是否登录) {
  Text("未登录")
}

2.4 常见条件场景

场景1:登录状态
if (this.是否登录) {
  // 显示用户信息
  Column() {
    Image($r("app.media.avatar"))
    Text(this.用户名)
    Button("退出登录")
  }
} else {
  // 显示登录按钮
  Column() {
    Text("请先登录")
    Button("立即登录")
  }
}
场景2:加载状态
if (this.是否加载中) {
  // 显示加载动画
  Column() {
    LoadingProgress()
      .width(50)
      .height(50)
    Text("加载中...")
  }
} else if (this.是否有错误) {
  // 显示错误信息
  Text("加载失败,请重试")
} else {
  // 显示内容
  List() {
    ForEach(this.数据列表, (项目) => { /* ... */ })
  }
}
场景3:空数据提示
if (this.列表.length == 0) {
  // 显示空状态
  Column() {
    Text("📭")
      .fontSize(60)
    Text("暂无数据")
      .fontColor("#999999")
  }
} else {
  // 显示列表
  ForEach(this.列表, (项目) => { /* ... */ })
}

三、动手实践

3.1 基础练习:登录状态切换

做一个根据登录状态显示不同内容的页面:

// 完整可运行代码,复制到 Index.ets 即可运行
@Entry
@Component
struct Index {
  @State 是否登录: boolean = false
  @State 用户名: string = "张三"
  @State 头像: string = "👤"

  build() {
    Column() {
      // 顶部导航栏
      Row() {
        Text("用户中心")
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
        
        if (this.是否登录) {
          Text("设置")
            .fontSize(14)
            .fontColor("#2196F3")
        }
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
      .padding(20)
      .backgroundColor('#FFFFFF')
      
      // 主要内容区域
      Column({ space: 20 }) {
        if (this.是否登录) {
          // 已登录状态
          this.已登录界面()
        } else {
          // 未登录状态
          this.未登录界面()
        }
      }
      .width('100%')
      .layoutWeight(1)
      .padding(20)
      
      // 底部切换按钮(仅用于演示)
      Button(this.是否登录 ? "退出登录(演示)" : "模拟登录(演示)")
        .width('90%')
        .backgroundColor(this.是否登录 ? '#F44336' : '#4CAF50')
        .onClick(() => {
          this.是否登录 = !this.是否登录
        })
        .margin({ bottom: 20 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
  
  // 已登录界面
  @Builder
  已登录界面() {
    Column({ space: 20 }) {
      // 用户信息卡片
      Column({ space: 15 }) {
        Text(this.头像)
          .fontSize(80)
          .backgroundColor('#E3F2FD')
          .borderRadius(50)
          .width(100)
          .height(100)
          .textAlign(TextAlign.Center)
        
        Text(this.用户名)
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
        
        Text("普通会员")
          .fontSize(14)
          .fontColor("#999999")
          .padding({ left: 10, right: 10, top: 3, bottom: 3 })
          .backgroundColor('#F5F5F5')
          .borderRadius(10)
      }
      .width('100%')
      .padding(30)
      .backgroundColor('#FFFFFF')
      .borderRadius(12)
      
      // 功能菜单
      Column({ space: 1 }) {
        this.菜单项("📋", "我的订单", "3个未完成")
        this.菜单项("❤️", "我的收藏", "12个商品")
        this.菜单项("🎫", "优惠券", "2张即将过期")
        this.菜单项("⚙️", "设置", "")
        this.菜单项("❓", "帮助与反馈", "")
      }
      .width('100%')
      .backgroundColor('#FFFFFF')
      .borderRadius(12)
      .clip(true)
      
      // 退出登录按钮
      Button("退出登录", { type: ButtonType.Capsule })
        .width('100%')
        .height(50)
        .backgroundColor('#FFFFFF')
        .fontColor('#F44336')
        .border({ width: 1, color: '#F44336' })
        .onClick(() => {
          this.是否登录 = false
        })
    }
  }
  
  // 未登录界面
  @Builder
  未登录界面() {
    Column({ space: 30 }) {
      // 提示图标
      Column({ space: 15 }) {
        Text("🔒")
          .fontSize(100)
        
        Text("您还未登录")
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
        
        Text("登录后可享受更多功能")
          .fontSize(14)
          .fontColor("#999999")
      }
      .margin({ top: 50 })
      
      // 登录按钮
      Column({ space: 15 }) {
        Button("立即登录", { type: ButtonType.Capsule })
          .width('100%')
          .height(50)
          .backgroundColor('#2196F3')
          .onClick(() => {
            this.是否登录 = true
          })
        
        Button("注册账号", { type: ButtonType.Capsule })
          .width('100%')
          .height(50)
          .backgroundColor('#FFFFFF')
          .fontColor('#2196F3')
          .border({ width: 1, color: '#2196F3' })
        
        Text("游客模式浏览")
          .fontSize(14)
          .fontColor("#999999")
          .margin({ top: 10 })
      }
      .width('100%')
      .padding({ left: 30, right: 30 })
    }
  }
  
  // 菜单项组件
  @Builder
  菜单项(图标: string, 标题: string, 提示: string) {
    Row() {
      Row({ space: 10 }) {
        Text(图标)
          .fontSize(20)
        Text(标题)
          .fontSize(16)
      }
      
      Row({ space: 5 }) {
        if (提示 != "") {
          Text(提示)
            .fontSize(12)
            .fontColor("#F44336")
        }
        Text(">")
          .fontSize(16)
          .fontColor("#CCCCCC")
      }
    }
    .width('100%')
    .height(55)
    .padding({ left: 15, right: 15 })
    .justifyContent(FlexAlign.SpaceBetween)
    .backgroundColor('#FFFFFF')
  }
}

3.2 进阶练习:加载状态管理

做一个带多种状态(加载中、成功、失败、空数据)的页面:

// 完整可运行代码,复制到 Index.ets 即可运行
@Entry
@Component
struct Index {
  @State 加载状态: string = "加载中"  // 加载中、成功、失败、空数据
  @State 数据列表: string[] = []
  @State 错误信息: string = ""

  build() {
    Column() {
      // 标题栏
      Row() {
        Text("数据列表")
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
        
        Row({ space: 10 }) {
          Text("模拟:")
            .fontSize(12)
            .fontColor("#999999")
          
          // 状态切换按钮(仅演示用)
          Text("加载")
            .fontSize(12)
            .padding(5)
            .backgroundColor(this.加载状态 == "加载中" ? '#2196F3' : '#F5F5F5')
            .fontColor(this.加载状态 == "加载中" ? '#FFFFFF' : '#333333')
            .onClick(() => this.模拟加载中())
          
          Text("成功")
            .fontSize(12)
            .padding(5)
            .backgroundColor(this.加载状态 == "成功" ? '#4CAF50' : '#F5F5F5')
            .fontColor(this.加载状态 == "成功" ? '#FFFFFF' : '#333333')
            .onClick(() => this.模拟成功())
          
          Text("失败")
            .fontSize(12)
            .padding(5)
            .backgroundColor(this.加载状态 == "失败" ? '#F44336' : '#F5F5F5')
            .fontColor(this.加载状态 == "失败" ? '#FFFFFF' : '#333333')
            .onClick(() => this.模拟失败())
          
          Text("空数据")
            .fontSize(12)
            .padding(5)
            .backgroundColor(this.加载状态 == "空数据" ? '#FF9800' : '#F5F5F5')
            .fontColor(this.加载状态 == "空数据" ? '#FFFFFF' : '#333333')
            .onClick(() => this.模拟空数据())
        }
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
      .padding(15)
      .backgroundColor('#FFFFFF')
      
      // 内容区域
      Column() {
        if (this.加载状态 == "加载中") {
          this.加载中界面()
        } else if (this.加载状态 == "失败") {
          this.失败界面()
        } else if (this.加载状态 == "空数据") {
          this.空数据界面()
        } else {
          this.成功界面()
        }
      }
      .width('100%')
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
  
  // 加载中界面
  @Builder
  加载中界面() {
    Column({ space: 15 }) {
      LoadingProgress()
        .width(60)
        .height(60)
        .color('#2196F3')
      
      Text("正在加载数据...")
        .fontSize(16)
        .fontColor("#666666")
    }
    .justifyContent(FlexAlign.Center)
  }
  
  // 失败界面
  @Builder
  失败界面() {
    Column({ space: 20 }) {
      Text("❌")
        .fontSize(60)
      
      Text("加载失败")
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor("#F44336")
      
      Text(this.错误信息 || "网络连接失败,请检查网络设置")
        .fontSize(14)
        .fontColor("#999999")
        .textAlign(TextAlign.Center)
      
      Button("重新加载", { type: ButtonType.Capsule })
        .width(150)
        .height(40)
        .backgroundColor('#2196F3')
        .onClick(() => {
          this.模拟加载中()
          setTimeout(() => this.模拟成功(), 1500)
        })
    }
    .justifyContent(FlexAlign.Center)
  }
  
  // 空数据界面
  @Builder
  空数据界面() {
    Column({ space: 15 }) {
      Text("📭")
        .fontSize(80)
      
      Text("暂无数据")
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor("#666666")
      
      Text("快去添加第一条数据吧")
        .fontSize(14)
        .fontColor("#999999")
      
      Button("添加数据", { type: ButtonType.Capsule })
        .width(150)
        .height(40)
        .backgroundColor('#4CAF50')
        .margin({ top: 10 })
        .onClick(() => {
          this.模拟成功()
        })
    }
    .justifyContent(FlexAlign.Center)
  }
  
  // 成功界面
  @Builder
  成功界面() {
    List({ space: 10 }) {
      ForEach(this.数据列表, (项目: string, 索引: number) => {
        ListItem() {
          Row() {
            Text(`${索引 + 1}. ${项目}`)
              .fontSize(16)
          }
          .width('100%')
          .height(60)
          .padding(15)
          .backgroundColor('#FFFFFF')
          .borderRadius(8)
        }
      })
    }
    .padding(15)
    
    // 刷新按钮
    Button("刷新数据")
      .width('90%')
      .height(45)
      .backgroundColor('#2196F3')
      .margin({ bottom: 20 })
      .onClick(() => {
        this.模拟加载中()
        setTimeout(() => {
          if (Math.random() > 0.3) {
            this.模拟成功()
          } else {
            this.模拟失败()
          }
        }, 1500)
      })
  }
  
  // 模拟各种状态
  模拟加载中() {
    this.加载状态 = "加载中"
  }
  
  模拟成功() {
    this.数据列表 = ["数据项1", "数据项2", "数据项3", "数据项4", "数据项5"]
    this.加载状态 = "成功"
  }
  
  模拟失败() {
    this.错误信息 = "服务器连接超时"
    this.加载状态 = "失败"
  }
  
  模拟空数据() {
    this.数据列表 = []
    this.加载状态 = "空数据"
  }
}

3.3 进阶练习:权限控制

做一个根据用户权限显示不同内容的页面:

// 完整可运行代码,复制到 Index.ets 即可运行
@Entry
@Component
struct Index {
  @State 用户角色: string = "游客"  // 游客、普通用户、VIP、管理员

  build() {
    Column() {
      // 标题
      Text("内容权限演示")
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin(20)
      
      // 角色切换(演示用)
      Scroll() {
        Row({ space: 10 }) {
          ForEach(["游客", "普通用户", "VIP", "管理员"], (角色: string) => {
            Text(角色)
              .fontSize(14)
              .padding({ left: 15, right: 15, top: 8, bottom: 8 })
              .backgroundColor(this.用户角色 == 角色 ? '#2196F3' : '#F5F5F5')
              .fontColor(this.用户角色 == 角色 ? '#FFFFFF' : '#333333')
              .borderRadius(20)
              .onClick(() => {
                this.用户角色 = 角色
              })
          })
        }
        .padding(15)
      }
      .scrollBar(BarState.Off)
      .scrollable(ScrollDirection.Horizontal)
      
      // 内容区域
      Column({ space: 15 }) {
        // 公开内容 - 所有人可见
        this.内容卡片("📢 公告", "欢迎访问我们的应用!", "公开", "#4CAF50")
        
        // 登录可见内容
        if (this.用户角色 != "游客") {
          this.内容卡片("📰 新闻", "今日最新资讯更新...", "登录用户", "#2196F3")
        }
        
        // VIP专属内容
        if (this.用户角色 == "VIP" || this.用户角色 == "管理员") {
          this.内容卡片("👑 VIP专区", "专属优惠和特权内容...", "VIP专属", "#FF9800")
        }
        
        // 管理员专属内容
        if (this.用户角色 == "管理员") {
          this.内容卡片("⚙️ 管理后台", "系统管理和数据统计...", "管理员", "#F44336")
        }
        
        // 提示信息
        this.权限提示()
      }
      .width('100%')
      .layoutWeight(1)
      .padding(15)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }
  
  // 内容卡片
  @Builder
  内容卡片(标题: string, 内容: string, 标签: string, 标签颜色: string) {
    Column({ space: 10 }) {
      Row() {
        Text(标题)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
        
        Text(标签)
          .fontSize(11)
          .fontColor('#FFFFFF')
          .padding({ left: 8, right: 8, top: 2, bottom: 2 })
          .backgroundColor(标签颜色)
          .borderRadius(10)
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
      
      Text(内容)
        .fontSize(14)
        .fontColor("#666666")
    }
    .width('100%')
    .padding(15)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
  }
  
  // 权限提示
  @Builder
  权限提示() {
    Column({ space: 5 }) {
      if (this.用户角色 == "游客") {
        Text("💡 提示:登录后可查看更多内容")
          .fontSize(12)
          .fontColor("#999999")
      } else if (this.用户角色 == "普通用户") {
        Text("💡 提示:升级VIP解锁更多特权")
          .fontSize(12)
          .fontColor("#FF9800")
      } else if (this.用户角色 == "VIP") {
        Text("✨ 您已享受VIP全部特权")
          .fontSize(12)
          .fontColor("#4CAF50")
      } else {
        Text("🔧 管理员模式已开启")
          .fontSize(12)
          .fontColor("#F44336")
      }
    }
    .margin({ top: 10 })
  }
}

四、知识总结

4.1 核心概念回顾

  1. if-else:根据条件显示不同内容
  2. 条件运算符:简化简单条件的写法
  3. 逻辑运算符:组合多个条件
  4. 常见场景:登录状态、加载状态、权限控制

4.2 条件渲染速查

// 基本if-else
if (条件) {
  // 真时显示
} else {
  // 假时显示
}

// 多条件判断
if (条件1) {
  // ...
} else if (条件2) {
  // ...
} else {
  // ...
}

// 三元运算符
Text(条件 ? "真" : "假")

// 逻辑运算符
if (条件1 && 条件2) { }    // 并且
if (条件1 || 条件2) { }    // 或者
if (!条件) { }              // 取反

4.3 常见场景模板

// 登录状态
if (this.是否登录) {
  // 显示用户信息
} else {
  // 显示登录按钮
}

// 加载状态
if (this.加载中) {
  // 显示加载动画
} else if (this.有错误) {
  // 显示错误
} else {
  // 显示内容
}

// 空数据
if (this.列表.length == 0) {
  // 显示空状态
} else {
  // 显示列表
}

4.4 常见错误提醒

错误现象 原因 解决方法
条件不生效 条件写错 检查条件表达式
两边都显示 if-else结构错误 检查花括号配对
界面闪烁 条件频繁变化 优化状态更新逻辑
嵌套太深 条件太多 考虑拆分组件

五、课后作业

5.1 巩固练习(必做)

练习1:成绩等级显示

输入成绩,根据分数显示不同等级和颜色:

  • 90-100:优秀(绿色)
  • 80-89:良好(蓝色)
  • 60-79:及格(橙色)
  • <60:不及格(红色)

练习2:夜间模式切换

做一个可以切换白天/夜间模式的应用:

  • 白天:白色背景,黑色文字
  • 夜间:深色背景,白色文字

练习3:表单验证

做一个注册表单:

  • 用户名不能为空
  • 密码至少6位
  • 两次密码要一致
  • 根据验证结果显示不同提示

5.2 创意编程(选做)

创意1:游戏角色选择

  • 选择不同角色显示不同属性
  • 战士:高攻击
  • 法师:高魔法
  • 牧师:高治疗

创意2:天气预报

  • 根据天气显示不同图标和背景
  • 晴天、雨天、雪天、多云

创意3:智能助手

  • 输入问题,根据关键词显示不同回答
  • “你好"→"你好!”
  • "时间"→显示当前时间
  • "帮助"→显示帮助信息

5.3 下篇预习

下一篇,我们将学习功能定义,封装可复用的代码。预习问题:

  1. 怎么把重复的代码提取出来?
  2. 怎么给代码起名字?
  3. 怎么使用封装好的代码?

恭喜你完成了第6篇的学习! 🎉

现在你已经掌握了条件渲染,可以做出根据状态动态变化的应用了。记住:if-else让界面更智能,条件渲染让应用更灵活

下节课,我们将学习如何封装可复用的代码!

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐