🌟 引言:組件化思維的價值

在現代鴻蒙應用開發中,組件化不僅是技術實現手段,更是架構設計的核心思想。通過將複雜界面拆分為獨立、可複用的自定義組件,開發者能夠構建出高內聚、低耦合的應用程序架構。ArkUI的組件系統讓每個UI單元都能擁有獨立的狀態管理和生命週期,大幅提升代碼的可維護性和團隊協作效率。

一、自定義組件基礎:從概念到實現

自定義組件是基於ArkUI聲明式語法構建的獨立UI單元,它封裝了特定的佈局、樣式和交互行為,可以在應用的不同部分多次複用。

1. 組件基本結構與裝飾器

@Component
struct UserCard {
  @State userName: string = '默認用户'
  @State isSelected: boolean = false

  build() {
    Column() {
      Image($r('app.media.avatar'))
        .width(60)
        .height(60)
        .borderRadius(30)
      
      Text(this.userName)
        .fontSize(16)
        .fontColor(this.isSelected ? '#007DFF' : '#182431')
    }
    .padding(10)
    .backgroundColor('#FFFFFF')
    .onClick(() => {
      this.isSelected = !this.isSelected
    })
  }
}

關鍵裝飾器解析:

  • @Component:將struct轉換為可複用的UI組件
  • @State:管理組件內部狀態,狀態變化自動觸發UI更新
  • @Entry:標識頁面入口組件(每個頁面唯一)

2. 組件的導出與導入

為了實現真正的複用,組件需要支持跨文件引用:

// UserCard.ets
@Component
export struct UserCard {  // 使用export關鍵字導出
  @Prop userName: string
  
  build() {
    // 組件實現
  }
}

// Index.ets  
import { UserCard } from './UserCard'  // 導入自定義組件

@Entry
@Component
struct MainPage {
  build() {
    Column() {
      UserCard({ userName: '張三' })
      UserCard({ userName: '李四' })
    }
  }
}
二、組件數據通信:多種場景下的信息流轉

組件通信是組件化架構的核心,鴻蒙提供了多種數據傳遞機制適應不同場景。

1. 父傳子:@Prop屬性的單向流動

@Prop允許父組件向子組件傳遞數據,建立單向綁定關係:

@Component
struct ProductItem {
  @Prop productName: string = '默認商品'  // 父組件傳遞的屬性
  @Prop price: number = 0
  @Prop isOnSale: boolean = false

  build() {
    Row() {
      Column() {
        Text(this.productName)
          .fontSize(16)
        Text(`¥${this.price}`)
          .fontColor(this.isOnSale ? '#FF3B30' : '#000000')
          .decoration({ type: this.isOnSale ? TextDecorationType.LineThrough : TextDecorationType.None })
      }
      if (this.isOnSale) {
        Text('特價')
          .fontColor('#FF3B30')
          .border({ width: 1, color: '#FF3B30' })
      }
    }
  }
}

// 父組件使用
ProductItem({ productName: '鴻蒙開發板', price: 299, isOnSale: true })

2. 子傳父:@Event事件回調機制

子組件通過事件通知父組件狀態變化,實現逆向通信:

// 子組件定義
@Component
struct SearchBar {
  @State searchText: string = ''
  @Event onSearch: (text: string) => void  // 定義事件回調

  build() {
    Row() {
      TextInput({ placeholder: '請輸入關鍵詞', text: this.searchText })
        .onChange((value: string) => {
          this.searchText = value
        })
      
      Button('搜索')
        .onClick(() => {
          this.onSearch(this.searchText)  // 觸發事件
        })
    }
  }
}

// 父組件使用
@Entry
@Component
struct ProductPage {
  build() {
    Column() {
      SearchBar({
        onSearch: (text: string) => {
          // 處理搜索邏輯
          this.performSearch(text)
        }
      })
    }
  }

  performSearch(keyword: string): void {
    console.info(`搜索關鍵詞: ${keyword}`)
    // 實際搜索實現
  }
}

3. 雙向同步:@Link的狀態共享

@Link建立父子組件間的雙向數據綁定,任何一方的修改都會同步到另一方:

@Component
struct ToggleSwitch {
  @Link isOn: boolean  // 雙向綁定

  build() {
    Toggle({ type: ToggleType.Switch, isOn: this.isOn })
      .onChange((value: boolean) => {
        this.isOn = value  // 修改同步到父組件
      })
  }
}

@Entry
@Component
struct SettingsPage {
  @State autoLogin: boolean = true  // 父組件狀態

  build() {
    Column() {
      Text(`自動登錄狀態: ${this.autoLogin ? '開啓' : '關閉'}`)
      ToggleSwitch({ isOn: $autoLogin })  // 使用$符號建立雙向綁定
    }
  }
}
三、組件組合與嵌套:構建複雜界面

通過組件的合理組合,可以構建出功能豐富且結構清晰的用户界面。

1. 容器組件的組合策略

// 基礎信息展示組件
@Component
struct UserInfo {
  @Prop user: UserModel
  
  build() {
    Row() {
      Image(this.user.avatar)
        .width(40)
        .height(40)
      Column() {
        Text(this.user.name)
        Text(this.user.title)
          .fontColor('#666666')
      }
    }
  }
}

// 操作按鈕組組件
@Component
struct ActionButtons {
  @Event onFollow: () => void
  @Event onMessage: () => void
  
  build() {
    Row() {
      Button('關注')
        .onClick(() => this.onFollow())
      Button('發消息')
        .onClick(() => this.onMessage())
    }
  }
}

// 組合成用户卡片組件
@Component
struct UserProfileCard {
  @Prop user: UserModel
  @Event onFollow: () => void
  
  build() {
    Column() {
      UserInfo({ user: this.user })
      ActionButtons({
        onFollow: this.onFollow.bind(this),
        onMessage: () => this.sendMessage()
      })
    }
  }
  
  sendMessage(): void {
    // 發送消息邏輯
  }
}

2. 插槽機制:@Builder的靈活運用

@Builder提供了一種更靈活的組件內容定製方式:

@Component
struct CardContainer {
  @BuilderParam header: () => void
  @BuilderParam content: () => void
  @BuilderParam footer: () => void

  build() {
    Column() {
      // 頭部插槽
      if (this.header) {
        this.header()
      }
      
      // 內容插槽  
      Column() {
        if (this.content) {
          this.content()
        }
      }
      .layoutWeight(1)

      // 底部插槽
      if (this.footer) {
        this.footer()
      }
    }
  }
}

// 使用構建器定製內容
CardContainer() {
  .header(() => {
    Text('卡片標題')
      .fontSize(18)
      .fontWeight(FontWeight.Bold)
  })
  .content(() => {
    Text('這是卡片的主要內容區域...')
  })
  .footer(() => {
    Button('確認操作')
  }
}
四、組件生命週期管理

自定義組件擁有完整的生命週期回調,允許開發者在特定時機執行邏輯。

1. 生命週期階段詳解

@Component
struct LifecycleDemo {
  @State data: string = ''
  
  // 組件即將出現時觸發
  aboutToAppear(): void {
    console.info('組件即將顯示')
    this.loadData()
  }
  
  // 組件即將消失時觸發  
  aboutToDisappear(): void {
    console.info('組件即將銷燬')
    this.cleanup()
  }
  
  // 組件佈局完成時觸發
  onPageShow(): void {
    console.info('頁面已顯示')
  }
  
  // 組件隱藏時觸發
  onPageHide(): void {
    console.info('頁面已隱藏')
  }

  build() {
    Text(this.data)
  }
  
  private loadData(): void {
    // 數據加載邏輯
  }
  
  private cleanup(): void {
    // 資源清理邏輯
  }
}

2. 生命週期最佳實踐

  • 數據加載:在aboutToAppear中執行,避免在build方法中阻塞渲染
  • 資源釋放:在aboutToDisappear中清理定時器、監聽器等資源
  • 狀態保存:在onPageHide中保存用户操作狀態
五、高級組件模式

1. 條件渲染控制

@Component
struct SmartContainer {
  @Prop condition: boolean
  @BuilderParam content: () => void
  @BuilderParam fallback: () => void = undefined

  build() {
    Column() {
      if (this.condition) {
        this.content()
      } else if (this.fallback) {
        this.fallback()
      } else {
        Text('暫無內容')
          .fontColor('#999999')
      }
    }
  }
}

2. 列表項組件優化

@Reusable  // 啓用組件複用
@Component
struct OptimizedListItem {
  @Prop item: ListItemModel
  @Prop onItemClick: (item: ListItemModel) => void

  build() {
    Row() {
      Image(this.item.cover)
        .width(80)
        .height(80)
      Column() {
        Text(this.item.title)
          .fontSize(16)
        Text(this.item.description)
          .maxLines(2)
      }
    }
    .onClick(() => {
      this.onItemClick?.(this.item)
    })
  }
}
六、組件設計最佳實踐

1. 單一職責原則

每個組件應該只負責一個特定的功能模塊。過於複雜的組件應該進行拆分。

2. 接口設計規範

  • 屬性命名:使用駝峯命名法,明確表達意圖
  • 事件定義:使用on前綴,如onValueChange
  • 默認值:為可選屬性提供合理的默認值
  • 類型校驗:使用TypeScript確保類型安全

3. 性能優化策略

  • 使用@Reusable裝飾器優化組件複用
  • 避免在build方法中創建新對象或函數
  • 合理使用@StorageLink進行狀態持久化
  • 複雜計算使用@Watch監聽器優化重渲染
💎 總結

自定義組件是鴻蒙應用架構的基石。通過掌握組件通信、生命週期管理和組合模式,開發者可以構建出高度可複用、易維護的UI組件體系。良好的組件設計不僅提升開發效率,也為後續的功能擴展和維護奠定堅實基礎。

本系列下一篇文章將探討《動效與交互:屬性動畫、轉場動畫與手勢處理》,深入分析如何為鴻蒙應用添加流暢的動畫效果和直觀的交互體驗。

進一步學習建議:在實際項目中,建議從簡單的展示組件開始,逐步添加交互邏輯和狀態管理。官方文檔中的自定義組件詳解提供了完整的API參考和最佳實踐示例。