状况同享-父子单向

**@Prop** 装修的变量能够和父组件建立单向的同步联系。**@Prop** 装修的变量是可变的,但是改变不会同步回其父组件。

@Entry
@Component
struct Index {
  @State
  money: number = 0
  build() {
    Column({ space: 20 }){
      Text('父组件:' + this.money)
        .onClick(() => {
          this.money ++
        })
      Child({ money: this.money })
    }
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
  }
}
@Component
struct Child {
  @Prop
  money: number
  build() {
    Text('子组件:' + this.money)
      .onClick(() => {
        this.money ++
      })
  }
}
  • 支撑类型 string、number、boolean、enum 类型
  • 子组件可修正 Prop 数据值,但不同步到父组件,父组件更新后覆盖子组件 Prop 数据
  • 子组件能够初始化默认值,留意:目前编译器会提示错误,请疏忽,下个版别将修正

状况同享-父子双向

子组件中被@Link装修的变量与其父组件中对应的数据源建立双向数据绑定。

1)简略类型 stringnumberbooleanenum

@Entry
@Component
struct Index {
  @State
  money: number = 0
  build() {
    Column({ space: 20 }){
      Text('父组件:' + this.money)
        .onClick(() => {
          this.money ++
        })
      Child({ money: $money })
    }
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
  }
}
@Component
struct Child {
  @Link
  money: number
  build() {
    Text('子组件:' + this.money)
      .onClick(() => {
        this.money ++
      })
  }
}

2)复杂类型 Objectclass

class Person {
  name: string
  age: number
}
@Entry
@Component
struct Index {
  @State
  person: Person = { name: 'jack', age: 18 }
  build() {
    Column({ space: 20 }){
      Text('父组件:' + `${this.person.name} 今年 ${ this.person.age } 岁`)
        .onClick(() => {
          this.person.age ++
        })
      Child({ person: $person })
    }
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
  }
}
@Component
struct Child {
  @Link
  person: Person
  build() {
    Text('子组件:' +  `${this.person.name} 今年 ${ this.person.age } 岁`)
      .onClick(() => {
        this.person.age ++
      })
  }
}
  • 父组件传值的时分需求 **this.**改成 $,子组件 @Link 修饰数据

3. 状况同享-子孙组件

@Provide@Consume,应用于与子孙组件的双向数据同步,应用于状况数据在多个层级之间传递的场景。
1)经过相同的变量名绑定

@Entry
@Component
struct Index {
  @Provide
  money: number = 0
  build() {
    Column({ space: 20 }) {
      Text('父组件:' + this.money)
        .onClick(() => {
          this.money++
        })
      Parent()
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}
@Component
struct Parent {
  @Consume
  money: number
  build() {
    Column({ space: 20 }) {
      Text('父组件:' + this.money)
        .onClick(() => {
          this.money++
        })
      Child()
    }
  }
}
@Component
struct Child {
  @Consume
  money: number
  build() {
    Text('子组件:' + this.money)
      .onClick(() => {
        this.money++
      })
  }
}

Object、class、string、number、boolean、enum 类型均支撑
经过相同的变量别号绑定 @Provide(‘key’) 和 @Consume(‘key’) key需求保持一致

4. 状况同享-状况监听器

如果开发者需求关注某个状况变量的值是否改变,能够运用 @Watch 为状况变量设置回调函数。

  • @State@Prop@Link 等装修器在 @Watch 装修之前
import promptAction from '@ohos.promptAction'
@Component
struct Child {
  @Prop
  @Watch('onActiveIndex')
  activeIndex: number
  onActiveIndex() {
    promptAction.showToast({ message: '监听改变' })
  }
  build() {
    Column() {
      Text('Child' + this.activeIndex)
    }
  }
}
@Entry
@Component
struct Index {
  @State activeIndex: number = 0
  onChange (index: number) {
    this.activeIndex = index
    promptAction.showToast({ message: '点击' })
  }
  build() {
    Navigation() {
      Child({ activeIndex: this.activeIndex })
    }.toolBar({
      items: [
        { value: '首页', action: () => this.onChange(0) },
        { value: '我的', action: () => this.onChange(1) },
      ]
    })
  }
}
  • 在第一次初始化的时分,@Watch装修的办法不会被调用

5. @Observed与@ObjectLink

之前咱们经过 赋值的方法 修正嵌套目标目标数组这类复杂数据来更新UI,会影响目标对应一切UI更新; 经过 @Observed@ObjectLink 能够优化这个问题;
运用过程:

  • 类 class 数据模拟需求界说经过结构函数,运用 @Observed 修饰这个类

  • 初始化数据:需求经过初始化结构函数的方法增加

  • 经过 @ObjectLink 相关目标,能够直接修正被相关目标来更新UI

需求:改造下知乎谈论案例
1)界说结构函数和运用@Observed 修饰符,以及初始化数据

models/index.ets

@Observed
export class ReplyItem {
  id: number
  avatar: string | Resource
  author: string
  content: string
  time: string
  area: string
  likeNum: number
  likeFlag?: boolean
  constructor(item: ReplyItem) {
    for (const key in item) {
      this[key] = item[key]
    }
  }
}
export const replyList: ReplyItem[] = [
  new ReplyItem({
    id: 1,
    avatar: 'https://www.6hu.cc/storage/2024/02/236124-Sr44E3.jpg?source=06d4cd63',
    author: '偏执狂-妄想家',
    content: '更何况还分到一个摩洛哥[惊喜]',
    time: '11-30',
    area: '海南',
    likeNum: 34
  }),
  new ReplyItem({
    id: 2,
    avatar: 'https://www.6hu.cc/storage/2024/02/236124-xbSGDR.jpg?source=32738c0c',
    author: 'William',
    content: '当年希腊但是把1:0发挥到极致了',
    time: '11-29',
    area: '北京',
    likeNum: 58
  }),
  new ReplyItem({
    id: 3,
    avatar: 'https://www.6hu.cc/storage/2024/02/236124-RXmpZ5.jpg?source=06d4cd63',
    author: 'Andy Garcia',
    content: '欧洲杯其实16队球队打正赛已经差不多,24队打正赛意味着正赛阶段在小组赛相同有弱队。',
    time: '11-28',
    area: '上海',
    likeNum: 10
  }),
  new ReplyItem({
    id: 4,
    avatar: 'https://www.6hu.cc/storage/2024/02/236124-g1VsgZ.jpg?source=06d4cd63',
    author: '正宗好鱼头',
    content: '的确眼红啊,亚洲就没这种球队,让中国队刷',
    time: '11-27',
    area: '香港',
    likeNum: 139
  }),
  new ReplyItem({
    id: 5,
    avatar: 'https://www.6hu.cc/storage/2024/02/236124-7u4cgx.jpg?source=06d4cd63',
    author: '柱子哥',
    content: '我是支撑扩展的,亚洲杯欧洲杯扩到32队,世界杯扩到64队才是好的,世界上有超越200支部队,欧洲区55支部队,亚洲区47支部队,即使如此也就六成呈现率',
    time: '11-27',
    area: '旧金山',
    likeNum: 29
  }),
  new ReplyItem({
    id: 6,
    avatar: 'https://www.6hu.cc/storage/2024/02/236124-Q8hIFQ.jpg?source=06d4cd63',
    author: '飞轩逸',
    content: '制止欧洲杯扩军之前,应该先制止世界杯扩军,或许至少把亚洲名额一半给欧洲。',
    time: '11-26',
    area: '里约',
    likeNum: 100
  })
]

2)嵌套的目标,或许数组中的目标,传入子组件,组件运用 @ObjectLink 修饰符获取数据

pages/Index.ets

import promptAction from '@ohos.promptAction'
import { ReplyItem, replyList } from '../models'
@Entry
@Component
struct Index {
  @State
  replyList: ReplyItem[] = replyList
  @State
  content: string = ''
  onReply() {
    const reply: ReplyItem = new ReplyItem({
      id: Math.random(),
      content: this.content,
      author: 'Zhousg',
      avatar: $r('app.media.avatar'),
      time: '12-01',
      likeNum: 0,
      area: '北京'
    })
    this.replyList.unshift(reply)
    this.content = ''
    promptAction.showToast({ message: '回复成功' })
  }
  build() {
    Stack() {
      Scroll() {
        Column() {
          NavComp()
          CommentComp()
          // space
          Divider()
            .strokeWidth(8)
            .color('#f5f5f5')
          // reply
          Column() {
            Text('回复 7')
              .width('100%')
              .margin({ bottom: 15 })
              .fontWeight(500)
            ForEach(this.replyList, (item: ReplyItem) => {
              ReplyComp({ item })
            })
          }
          .padding({ left: 15, right: 15, top: 15 })
        }
      }
      .padding({ bottom: 50 })
      Row() {
        TextInput({ placeholder: '回复~', text: this.content })
          .placeholderColor('#c3c4c5')
          .layoutWeight(1)
          .onChange((value) => {
            this.content = value
          })
        Text('发布')
          .fontSize(14)
          .fontColor('#09f')
          .margin({ left: 15 })
          .onClick(() => {
            this.onReply()
          })
      }
      .width('100%')
      .height(50)
      .padding({ left: 15, right: 15 })
      .position({ y: '100%' })
      .translate({ y: -50 })
      .backgroundColor('#fff')
      .border({ width: { top: 0.5 }, color: '#e4e4e4' })
    }
  }
}
@Component
struct ReplyComp {
  @ObjectLink
  item: ReplyItem
  onLike() {
    if (this.item.likeFlag) {
      this.item.likeNum--
      this.item.likeFlag = false
      promptAction.showToast({ message: '取消点赞' })
    } else {
      this.item.likeNum++
      this.item.likeFlag = true
      promptAction.showToast({ message: '点赞成功' })
    }
  }
  build() {
    Row() {
      Image(this.item.avatar)
        .width(32)
        .height(32)
        .borderRadius(16)
      Column() {
        Text(this.item.author)
          .fontSize(15)
          .fontWeight(FontWeight.Bold)
          .margin({ bottom: 5 })
        Text(this.item.content)
          .margin({ bottom: 5 })
          .fontColor('#565656')
          .lineHeight(20)
        Row() {
          Text(`${this.item.time}•IP 属地${this.item.area}`)
            .layoutWeight(1)
            .fontSize(14)
            .fontColor('#c3c4c5')
          Row() {
            Image($r('app.media.heart'))
              .width(14)
              .height(14)
              .fillColor(this.item.likeFlag ? '#ff6600' : '#c3c4c5')
              .margin({ right: 4 })
            Text(this.item.likeNum.toString())
              .fontSize(14)
              .fontColor(this.item.likeFlag ? '#ff6600' : '#c3c4c5')
          }
          .onClick(() => {
            this.onLike()
          })
        }
      }
      .layoutWeight(1)
      .padding({ left: 10 })
      .alignItems(HorizontalAlign.Start)
    }
    .width('100%')
    .padding({ bottom: 15 })
    .alignItems(VerticalAlign.Top)
  }
}
@Component
struct NavComp {
  build() {
    // nav
    Row() {
      Row() {
        Image($r('app.media.ic_public_arrow_left'))
          .width(12)
          .height(12)
          .fillColor('#848484')
      }
      .width(24)
      .height(24)
      .borderRadius(12)
      .backgroundColor('#f5f5f5')
      .justifyContent(FlexAlign.Center)
      .margin({ left: 13 })
      Text('谈论回复')
        .padding({ right: 50 })
        .textAlign(TextAlign.Center)
        .fontSize(18)
        .layoutWeight(1)
    }
    .height(50)
  }
}
@Component
struct CommentComp {
  build() {
    // comment
    Row() {
      Image('https://www.6hu.cc/storage/2024/02/236124-EyhPdV.jpg?source=c885d018')
        .width(32)
        .height(32)
        .borderRadius(16)
      Column() {
        Text('欧洲足球锦标赛')
          .fontSize(15)
          .fontWeight(FontWeight.Bold)
          .margin({ bottom: 5 })
        Text('14-0!欧洲杯超级惨案+刷爆纪录!姆巴佩帽子戏法,法国7连胜,怎么点评这场竞赛?')
          .margin({ bottom: 5 })
          .fontColor('#565656')
          .lineHeight(20)
        Row() {
          Text('10-21•IP 属地辽宁')
            .layoutWeight(1)
            .fontSize(14)
            .fontColor('#c3c4c5')
          Row() {
            Image($r('app.media.heart'))
              .width(14)
              .height(14)
              .fillColor('#c3c4c5')
              .margin({ right: 4 })
            Text('100')
              .fontSize(14)
              .fontColor('#c3c4c5')
          }
        }
      }
      .layoutWeight(1)
      .padding({ left: 10 })
      .alignItems(HorizontalAlign.Start)
    }
    .width('100%')
    .padding({ left: 15, right: 15, bottom: 15 })
    .alignItems(VerticalAlign.Top)
  }
}

留意:

  • 目标需求经过结构函数初始化

  • 需求嵌套组件,因为需求运用 @ObjectLink

关注公众号:Android老皮!!!欢迎大家来找我讨论沟通