HarmonyOS NEXT 实战系列04-组件状态

举报
yd_234838830 发表于 2025/03/26 14:19:54 2025/03/26
【摘要】 自定义组件拥有变量,变量必须被装饰器装饰才可以成为状态变量,状态变量的改变会引起UI的渲染刷新。如果不使用状态变量,UI只能在初始化时渲染,后续将不会再刷新。 下图展示了State和View(UI)之间的关系。View(UI):UI渲染,指将build方法内的UI描述和@Builder装饰的方法内的UI描述映射到界面。State:状态,指驱动UI更新的数据。用户通过触发组件的事件方法,改变状...

自定义组件拥有变量,变量必须被装饰器装饰才可以成为状态变量,状态变量的改变会引起UI的渲染刷新。如果不使用状态变量,UI只能在初始化时渲染,后续将不会再刷新。 下图展示了State和View(UI)之间的关系。

image.png

View(UI):UI渲染,指将build方法内的UI描述和@Builder装饰的方法内的UI描述映射到界面。
State:状态,指驱动UI更新的数据。用户通过触发组件的事件方法,改变状态数据。状态数据的改变,引起UI的重新渲染。

  1. 组件状态-@State
    @State装饰的变量,或称为状态变量,一旦变量拥有了状态属性,就可以触发其直接绑定UI组件的刷新。当状态改变时,UI会发生对应的渲染改变。

image.png

简单类型变量

@Entry
@Component
struct TestPage {
  @State
  count: number = 0
  
  build() {
    Column({ space: 50 }) {
      Row() {
        Text('-')
          .textButton()
          .onClick(() => {
            this.count--
          })
        Text(this.count.toString())
          .padding(15)
        Text('+')
          .textButton()
          .onClick(() => {
            this.count++
          })
      }
    }
    .width('100%')
    .height('100%')
    .margin({ top: 50 })
  }
}

@Extend(Text)
function textButton() {
  .fontSize(20)
  .backgroundColor('#CCCCCC')
  .width(32)
  .aspectRatio(1)
  .borderRadius(16)
  .textAlign(TextAlign.Center)
}

对象类型变量

@Entry
@Component
struct TestPage {
  @State
  students: string[] = ['小红', '小明']
  
  build() {
      Column({ space: 10 }) {
        ForEach(this.students, (item: string, i) => {
          Row({ space: 10 }){
            Text(item)
            Text('-')
              .textButton()
              .onClick(() => {
                // 从索引x处,删除x条
                this.students.splice(i, 1)
              })
          }
        })
        Button('添加学生')
          .onClick(() => {
            // 追加
            this.students.push('小芳')
          })
      }
    }
    .width('100%')
    .height('100%')
    .margin({ top: 50 })
  }
}

@Extend(Text)
function textButton() {
  .fontSize(20)
  .backgroundColor('#CCCCCC')
  .width(32)
  .aspectRatio(1)
  .borderRadius(16)
  .textAlign(TextAlign.Center)
}

数组类型变量

interface Person {
  name: string
  age: number
}

@Entry
@Component
struct TestPage {
  @State
  person: Person = { name: 'Jack', age: 18 }

  build() {
    Column({ space: 50 }) {
      Row({ space: 10 }){
        Text(this.person.name)
        Text(this.person.age.toString())
        Button('明年')
          .onClick(() => {
            this.person.age ++
          })
      }
    }
    .width('100%')
    .height('100%')
    .margin({ top: 50 })
  }
}

2. 组件状态-@Prop
@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。

1)自定义组件

在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。

可组合:允许开发者组合使用系统组件、及其属性和方法。
可重用:自定义组件可以被其他组件重用,并作为不同的实例在不同的父组件或容器中使用。
数据驱动UI更新:通过状态变量的改变,来驱动UI的刷新。

@Component
struct MyComponent {
  build() {
    // 组件结构
  }
}

尝试:提取 counter 组件

@Entry
@Component
struct TestPage {

  build() {
    Column({ space: 50 }) {
      CounterComp()
      CounterComp()
    }
    .width('100%')
    .height('100%')
    .margin({ top: 50 })
  }
}

@Component
struct CounterComp {
  @State count: number = 0

  build() {
    Row() {
      Text('-')
        .textButton()
        .onClick(() => {
          this.count--
        })
      Text(this.count.toString())
        .padding(15)
      Text('+')
        .textButton()
        .onClick(() => {
          this.count++
        })
    }
  }
}

@Extend(Text)
function textButton() {
  .fontSize(20)
  .backgroundColor('#CCCCCC')
  .width(32)
  .aspectRatio(1)
  .borderRadius(16)
  .textAlign(TextAlign.Center)
}

2)父子单向同步

@Entry
@Component
struct TestPage {
  @State count: number = 0

  build() {
    Column({ space: 50 }) {
      // Prop 父传值给子
      CounterComp({ count: this.count })
      CounterComp({ count: this.count })
    }
    .width('100%')
    .height('100%')
    .margin({ top: 50 })
  }
}

@Component
struct CounterComp {
  @Prop @Require count: number

  build() {
    Row() {
      Text('-')
        .textButton()
        .onClick(() => {
          this.count--
        })
      Text(this.count.toString())
        .padding(15)
      Text('+')
        .textButton()
        .onClick(() => {
          this.count++
        })
    }
  }
}

@Extend(Text)
function textButton() {
  .fontSize(20)
  .backgroundColor('#CCCCCC')
  .width(32)
  .aspectRatio(1)
  .borderRadius(16)
  .textAlign(TextAlign.Center)
}

注意:

虽然 @Prop 修饰的状态不会同步到父,但是字组件UI是会影响的
可以加上 @Require 代表必传,可省略初始值
3. 组件状态-@Link
子组件中被@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。

@Entry
@Component
struct TestPage {
  @State count: number = 0

  build() {
    Column({ space: 50 }) {
      // Link 父同步子,子同步父
      CounterComp({ count: this.count })
      CounterComp({ count: this.count })
    }
    .width('100%')
    .height('100%')
    .margin({ top: 50 })
  }
}

@Component
struct CounterComp {
  @Link count: number

  build() {
    Row() {
      Text('-')
        .textButton()
        .onClick(() => {
          this.count--
        })
      Text(this.count.toString())
        .padding(15)
      Text('+')
        .textButton()
        .onClick(() => {
          this.count++
        })
    }
  }
}

@Extend(Text)
function textButton() {
  .fontSize(20)
  .backgroundColor('#CCCCCC')
  .width(32)
  .aspectRatio(1)
  .borderRadius(16)
  .textAlign(TextAlign.Center)
}
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。