Harmony开发之循环渲染与条件渲染——动态列表的实现

引入:聊天消息列表场景

在日常应用中,我们经常需要展示动态数据列表,比如聊天消息、商品列表、新闻资讯等。这些场景的共同特点是:数据量可能很大,需要根据数据状态动态渲染不同的UI组件。在HarmonyOS开发中,ForEach循环渲染和if/else条件渲染正是解决这类问题的核心工具。

一、ForEach循环渲染

核心概念

ForEach接口基于数组类型数据进行循环渲染,需要与容器组件配合使用。它会在首次渲染时加载数据源的所有数据,并为每个数据项创建对应的组件。

基本用法

// 文件:pages/Index.ets
@Entry
@Component
struct MessageList {
  @State messageList: Array<string> = ['你好', '今天天气不错', '晚上一起吃饭吗?']
  
  build() {
    List() {
      ForEach(this.messageList, (item: string, index: number) => {
        ListItem() {
          Text(item)
            .fontSize(18)
            .margin({ top: 10, bottom: 10 })
        }
      }, (item: string) => item) // 键值生成器
    }
    .width('100%')
    .height('100%')
  }
}

键值生成规则

ForEach会为每个数组元素生成唯一键值,用于标识对应的组件。当键值变化时,框架会基于新键值创建新组件。

// 自定义键值生成器
ForEach(this.messageList, (item: string, index: number) => {
  ListItem() {
    Text(item)
  }
}, (item: string, index: number) => `${index}_${item}`)

二、if/else条件渲染

核心概念

条件渲染可根据应用的不同状态,使用if、else和else if渲染对应状态下的UI内容。@State定义的变量归父组件所有,子组件通过@Link装饰器引用状态。

基本用法

// 文件:pages/Index.ets
@Entry
@Component
struct ChatPage {
  @State hasNewMessage: boolean = true
  @State messageType: string = 'text' // text | image | video
  
  build() {
    Column() {
      // 条件渲染新消息提示
      if (this.hasNewMessage) {
        Text('有新消息')
          .backgroundColor('#ff4757')
          .fontColor(Color.White)
          .padding(10)
      }
      
      // 多条件分支
      if (this.messageType === 'text') {
        Text('这是一条文本消息')
      } else if (this.messageType === 'image') {
        Image($r('app.media.message_image'))
          .width(200)
          .height(200)
      } else {
        Text('视频消息')
      }
    }
  }
}

三、综合实战:聊天消息列表

数据结构定义

// 文件:model/Message.ts
export class Message {
  id: string = ''
  content: string = ''
  type: string = 'text' // text | image | system
  time: string = ''
  isMine: boolean = false
  status: string = 'sending' // sending | sent | failed
}

完整实现

// 文件:pages/ChatDetail.ets
import { Message } from '../model/Message'

@Entry
@Component
struct ChatDetail {
  @State messageList: Array<Message> = [
    { id: '1', content: '你好', type: 'text', time: '10:30', isMine: false, status: 'sent' },
    { id: '2', content: '今天天气不错', type: 'text', time: '10:31', isMine: true, status: 'sent' },
    { id: '3', content: '晚上一起吃饭吗?', type: 'text', time: '10:32', isMine: false, status: 'sent' }
  ]
  
  build() {
    List() {
      ForEach(this.messageList, (item: Message) => {
        ListItem() {
          // 根据消息类型和发送者渲染不同样式
          if (item.isMine) {
            this.MyMessage(item)
          } else {
            this.FriendMessage(item)
          }
        }
      }, (item: Message) => item.id)
    }
    .width('100%')
    .height('100%')
  }
  
  @Builder
  MyMessage(item: Message) {
    Column() {
      Text(item.content)
        .fontSize(16)
        .backgroundColor('#007AFF')
        .fontColor(Color.White)
        .padding(10)
        .borderRadius(10)
      
      // 消息状态
      if (item.status === 'sending') {
        Text('发送中...')
          .fontSize(12)
          .fontColor('#666')
      } else if (item.status === 'failed') {
        Text('发送失败')
          .fontSize(12)
          .fontColor('#ff3b30')
      }
    }
    .alignItems(HorizontalAlign.End)
    .margin({ right: 10 })
  }
  
  @Builder
  FriendMessage(item: Message) {
    Column() {
      Text(item.content)
        .fontSize(16)
        .backgroundColor('#E5E5EA')
        .padding(10)
        .borderRadius(10)
    }
    .alignItems(HorizontalAlign.Start)
    .margin({ left: 10 })
  }
}

四、性能优化建议

  1. 合理使用键值生成器:确保键值唯一且稳定,避免使用索引作为唯一键值
  2. 避免嵌套过深:条件渲染嵌套层数不宜过多,否则会影响性能
  3. 数据量控制:对于超长列表,建议使用LazyForEach懒加载组件
  4. 组件复用:使用@Builder构建可复用组件,减少重复代码

总结

ForEach循环渲染和if/else条件渲染是HarmonyOS开发中处理动态数据的核心能力。ForEach负责遍历数据源并生成对应的UI组件,而条件渲染则根据数据状态动态展示不同的UI内容。两者结合使用,可以轻松实现复杂的动态列表场景,如聊天消息、商品列表、新闻资讯等。

行动建议

  • 在开发列表页面时,优先考虑使用ForEach进行数据遍历
  • 根据业务需求合理使用条件渲染,避免过度嵌套
  • 注意键值生成规则,确保组件能够正确复用
  • 对于大数据量场景,及时采用LazyForEach进行性能优化
posted @ 2025-12-24 10:33  wrystart  阅读(2)  评论(0)    收藏  举报