引入:聊天消息列表場景

在日常應用中,我們經常需要展示動態數據列表,比如聊天消息、商品列表、新聞資訊等。這些場景的共同特點是:數據量可能很大,需要根據數據狀態動態渲染不同的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進行性能優化