编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

鸿蒙开发(八十六):ForEach 子组件创建规则

wxchong 2024-07-29 08:03:34 开源技术 10 ℃ 0 评论

这一节,我们来观察 ForEach 内部是如何运作的。理解这个非常重要!!!希望大家能够掌握。

首先,定义一个数据类 Article,里面只有一个属性 title。

/**
 * 文章
 */
class Article {
  /**
   * 标题
   */
  title: string

  constructor(title: string) {
    this.title = title
  }
}

然后,使用 @Observed 装饰 Article 类,因为待会要修改 Article 内部数据,如果不使用 @Observed 进行装饰,数据源无法感知它内部被修改,UI 也就无法被刷新。

/**
 * 文章
 */
@Observed
class Article {
  /**
   * 标题
   */
  title: string

  constructor(title: string) {
    this.title = title
  }
}

接着,定义展示数组元素的子组件 Item。

其中,article 是一个被 @ObjectLink 装饰的状态变量,类型为 Article。

重写 aboutToAppear 生命周期函数,每当组件被创建时调用。

在 build 函数中使用 Text 展示文章标题,并添加点击事件,点击时修改文本标题,观察 ForEach 的变化。

@Component
struct Item {
  @ObjectLink article: Article

  aboutToAppear() {
    console.log(`组件已创建:${this.article.title}`)
  }

  build() {
    Text(this.article.title)
      .fontSize(30)
      .margin(10)
      .onClick(() => {
        this.article.title = "子组件修改"
      })
  }
}

接下来,编写 Index 组件。

定义一个 @State 装饰的状态变量 articles 数组,并初始化它。

@Entry
@Component
struct Index {
  /**
   * 姓名列表
   */
  @State articles: Article[] = [
    new Article("javascript"),
    new Article("typescript"),
    new Article("harmonyos"),
  ]
}

最后,在 build 函数里:

  1. 添加一个 Button,点击时修改第一项数据。
  2. 使用 ForEach 遍历 articles 数组。
  3. 自定义 ForEach 的第三个参数 keyGenerator 函数,键值生成规则为 index + "_" + JSON.stringify(item),在函数内打印日志。
@Entry
@Component
struct Index {
  ...

  build() {
    Column() {
      Button("修改")
        .onClick(() => {
          this.articles[0] = new Article("按钮修改")
        })
      ForEach(this.articles, (item: Article) => {
        Item({ article: item })
      }, (item: Article, index: number) => {
        const result = index + "_" + JSON.stringify(item)
        console.log(result)
        return result
      })
    }
    .width('100%')
  }
}

完整代码:

/**
 * 文章
 */
@Observed
class Article {
  /**
   * 标题
   */
  title: string

  constructor(title: string) {
    this.title = title
  }
}

@Entry
@Component
struct Index {
  /**
   * 姓名列表
   */
  @State articles: Article[] = [
    new Article("javascript"),
    new Article("typescript"),
    new Article("harmonyos"),
  ]

  build() {
    Column() {
      Button("修改")
        .onClick(() => {
          this.articles[0] = new Article("按钮修改")
        })
      ForEach(this.articles, (item: Article) => {
        Item({ article: item })
      }, (item: Article, index: number) => {
        const result = index + "_" + JSON.stringify(item)
        console.log(result)
        return result
      })
    }
    .width('100%')
  }
}

@Component
struct Item {
  @ObjectLink article: Article

  aboutToAppear() {
    console.log(`组件已创建:${this.article.title}`)
  }

  build() {
    Text(this.article.title)
      .fontSize(30)
      .margin(10)
      .onClick(() => {
        this.article.title = "子组件修改"
      })
  }
}

运行结果:

控制台输出:

0_{"title":"javascript"}
1_{"title":"typescript"}
2_{"title":"harmonyos"}
组件已创建:javascript
组件已创建:typescript
组件已创建:harmonyos

从运行结果来看,ForEach 首次运行做了两件事:

  1. 为数组中所有元素生成唯一键值。
  2. 为数组中所有元素创建组件。

接下来,点击其中一个子项,例如“javascript”。

控制台:

从运行结果来看,修改对象属性时,刷新UI(“javascript”变成了“子组件修改”),但 ForEach 无任何变化,即没有重新生成键值,也没有重新生成组件。

最后,我们点击修改按钮看看。

控制台:

0_{"title":"按钮修改"}
1_{"title":"typescript"}
2_{"title":"harmonyos"}
组件已创建:按钮修改

从运行结果来看,程序发生了两件事:

  1. ForEach 为所有元素重新生成键值。
  2. ForEach 为变化的元素创建新组件。

综上所述:

ForEach 在首次渲染时:

  1. 为所有元素创建键值。
  2. 为所有元素创建组件。

在非首次渲染时:

  1. 为所有元素重新创建键值。
  2. 为变化的元素创建新组件。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表