鴻蒙自定義元件生命週期

龙儿筝發表於2024-11-10

在開始之前,我們先明確自定義元件和頁面的關係:

  • 自定義元件:@Component裝飾的UI單元,可以組合多個系統元件實現UI的複用,可以呼叫元件的生命週期。
  • 頁面:即應用的UI頁面。可以由一個或者多個自定義元件組成,@Entry裝飾的自定義元件為頁面的入口元件,即頁面的根節點,一個頁面有且僅能有一個@Entry。只有被@Entry裝飾的元件才可以呼叫頁面的生命週期。

頁面生命週期,即被@Entry裝飾的元件生命週期,提供以下生命週期介面:

  • onPageShow:頁面每次顯示時觸發一次,包括路由過程、應用進入前臺等場景。
  • onPageHide:頁面每次隱藏時觸發一次,包括路由過程、應用進入後臺等場景。
  • onBackPress:當使用者點選返回按鈕時觸發。

元件生命週期,即一般用@Component裝飾的自定義元件的生命週期,提供以下生命週期介面:

  • aboutToAppear:元件即將出現時回撥該介面,具體時機為在建立自定義元件的新例項後,在執行其build()函式之前執行。
  • onDidBuild:元件build()函式執行完成之後回撥該介面,不建議在onDidBuild函式中更改狀態變數、使用animateTo等功能,這可能會導致不穩定的UI表現。
  • aboutToDisappear:aboutToDisappear函式在自定義元件析構銷燬之前執行。不允許在aboutToDisappear函式中改變狀態變數,特別是@Link變數的修改可能會導致應用程式行為不穩定。

生命週期流程如下圖所示,下圖展示的是被@Entry裝飾的元件(頁面)生命週期。
img1
以下示例展示了生命週期的呼叫時機:

// Index.ets
import { router } from '@kit.ArkUI';

@Entry
@Component
struct MyComponent {
  @State showChild: boolean = true;
  @State btnColor:string = "#FF007DFF";

  // 只有被@Entry裝飾的元件才可以呼叫頁面的生命週期
  onPageShow() {
    console.info('Index onPageShow');
  }
  // 只有被@Entry裝飾的元件才可以呼叫頁面的生命週期
  onPageHide() {
    console.info('Index onPageHide');
  }

  // 只有被@Entry裝飾的元件才可以呼叫頁面的生命週期
  onBackPress() {
    console.info('Index onBackPress');
    this.btnColor ="#FFEE0606";
    return true // 返回true表示頁面自己處理返回邏輯,不進行頁面路由;返回false表示使用預設的路由返回邏輯,不設定返回值按照false處理
  }

  // 元件生命週期
  aboutToAppear() {
    console.info('MyComponent aboutToAppear');
  }

  // 元件生命週期
  onDidBuild() {
    console.info('MyComponent onDidBuild');
  }

  // 元件生命週期
  aboutToDisappear() {
    console.info('MyComponent aboutToDisappear');
  }

  build() {
    Column() {
      // this.showChild為true,建立Child子元件,執行Child aboutToAppear
      if (this.showChild) {
        Child()
      }
      // this.showChild為false,刪除Child子元件,執行Child aboutToDisappear
      Button('delete Child')
        .margin(20)
        .backgroundColor(this.btnColor)
        .onClick(() => {
        this.showChild = false;
      })
      // push到page頁面,執行onPageHide
      Button('push to next page')
        .onClick(() => {
          router.pushUrl({ url: 'pages/page' });
        })
    }
  }
}

@Component
struct Child {
  @State title: string = 'Hello World';
  // 元件生命週期
  aboutToDisappear() {
    console.info('[lifeCycle] Child aboutToDisappear');
  }

  // 元件生命週期
  onDidBuild() {
    console.info('[lifeCycle] Child onDidBuild');
  }

  // 元件生命週期
  aboutToAppear() {
    console.info('[lifeCycle] Child aboutToAppear');
  }

  build() {
    Text(this.title)
      .fontSize(50)
      .margin(20)
      .onClick(() => {
        this.title = 'Hello ArkUI';
      })
  }
}

// page.ets
@Entry
@Component
struct page {
  @State textColor: Color = Color.Black;
  @State num: number = 0;

  onPageShow() {
    this.num = 5;
  }

  onPageHide() {
    console.log("page onPageHide");
  }

  onBackPress() { // 不設定返回值按照false處理
    this.textColor = Color.Grey;
    this.num = 0;
  }

  aboutToAppear() {
    this.textColor = Color.Blue;
  }

  build() {
    Column() {
      Text(`num 的值為:${this.num}`)
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .fontColor(this.textColor)
        .margin(20)
        .onClick(() => {
          this.num += 5;
        })
    }
    .width('100%')
  }
}

以上示例中,Index頁面包含兩個自定義元件,一個是被@Entry裝飾的MyComponent,也是頁面的入口元件,即頁面的根節點;一個是Child,是MyComponent的子元件。只有@Entry裝飾的節點才可以使頁面級別的生命週期方法生效,因此在MyComponent中宣告當前Index頁面的頁面生命週期函式(onPageShow / onPageHide / onBackPress)。MyComponent和其子元件Child分別宣告瞭各自的元件級別生命週期函式(aboutToAppear / onDidBuild/aboutToDisappear)。

  • 應用冷啟動的初始化流程為:MyComponent aboutToAppear --> MyComponent build --> MyComponent onDidBuild--> Child aboutToAppear --> Child build --> Child onDidBuild --> Index onPageShow。
  • 點選“delete Child”,if繫結的this.showChild變成false,刪除Child元件,會執行Child aboutToDisappear方法。
  • 點選“push to next page”,呼叫router.pushUrl介面,跳轉到另外一個頁面,當前Index頁面隱藏,執行頁面生命週期Index onPageHide。此處呼叫的是router.pushUrl介面,Index頁面被隱藏,並沒有銷燬,所以只呼叫onPageHide。跳轉到新頁面後,執行初始化新頁面的生命週期的流程。
  • 如果呼叫的是router.replaceUrl,則當前Index頁面被銷燬,執行的生命週期流程將變為:Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。上文已經提到,元件的銷燬是從元件樹上直接摘下子樹,所以先呼叫父元件的aboutToDisappear,再呼叫子元件的aboutToDisappear,然後執行初始化新頁面的生命週期流程。
  • 點選返回按鈕,觸發頁面生命週期Index onBackPress,且觸發返回一個頁面後會導致當前Index頁面被銷燬。
  • 最小化應用或者應用進入後臺,觸發Index onPageHide。當前Index頁面沒有被銷燬,所以並不會執行元件的aboutToDisappear。應用回到前臺,執行Index onPageShow。
  • 退出應用,執行Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。

相關文章