组件状态共享2

2024-01-28  本文已影响0人  家乡的蝈蝈

1、组件状态共享2

1.1、状态共享-状态监听器

修饰符: entry、component、State、Prop、Link、Provide、Consume
  关注某个状态变量的值是否改变,可以使用 @Watch 为状态变量设置回调函数。
  Watch("回调函数名")中的回调必须在组件中声明,该函数接收一个参数,参数为修改的属性名
注意:Watch修饰符要写在 State Prop Link Provide Consume的修饰符下面,否则会有问题

@State
  @Watch('updateMessage') // Watch("回调函数名"),在state后面
  num:number = 0
  updateMessage() {
    promptAction.showToast({message:this.num.toString()})
  }

有了watch 我们就可以随心所欲的搞监听了,比如
● 父组件数据变化了, 子组件随机而动
● 子组件双向更新了父组件数据,父组件随机而动

 @Provide('aa')
  @Watch('updateMoney')
  money:number = 1000 // Provide跨组件提供数据,实现双向绑定,爷爷提供数据
  updateMoney() {
    promptAction.showToast({message:"钱变了"})
  }

1.2、@Observed和@ObjectLink

  封装的组件没办法做双向更新同步(传入Link修饰的数据必须得是最外层的 State数据,使用for循环最外层就不是state修饰了,即必须是根组件的state数据,不能是循环出来的数据),那么ArtTS支持 Observed和@ObjectLink来实现这个需求
  使用步骤:
● 类 class 数据需要定义构造函数,使用 @Observed 修饰这个类
● 初始化数据:需要通过初始化构造函数的方式添加(不能使用字面量{}来构建)
● 通过 @ObjectLink 关联对象,可以直接修改被关联对象来更新UI

@Entry
@Component
struct ObjectLinkCase {
  @State message: string = 'Hello World'
  @State
  list:FoodObjectClass[] = [new FoodObjectClass({
    order_id: 1,
    food_name: '鱼香肉丝',
    food_price: 18.8,
    food_count: 1
  }), new FoodObjectClass({
    order_id: 2,
    food_name: '粗溜丸子',
    food_price: 26,
    food_count: 2
  }),new FoodObjectClass({
    order_id: 3,
    food_name: '杂粮煎饼',
    food_price: 12,
    food_count: 1
  })]

  build() {
    Row() {
      Column({space:20}) {
        ForEach(this.list, (item:FoodObjectClass)=>{
          FoodItem({item:item}) // 传入的item的对象的类被Observed
        })
        BottonCard({myList:$list})
      }
      .width('100%')
    }
    .height('100%')
  }
}

@Extend(Text)
function AddTextStyle() {
 .width(40).height(40).borderRadius(20).backgroundColor(Color.Gray)
  .textAlign(TextAlign.Center).fontSize(20)
}

@Extend(Text)
function TextStyle() {
  .layoutWeight(1).textAlign(TextAlign.Center).fontSize(20)
}

@Component
struct FoodItem {
  @ObjectLink
  item:FoodObjectClass // 使用ObjectLink接收对象,此时父子组件具备双向更新
  build() {
    Row() {
      Text(this.item.food_name).TextStyle()
      Text(this.item.food_price.toFixed(2)).TextStyle()
      Row() {
          Text('-').AddTextStyle()
            .onClick(() => {
              this.item.food_count--
            })
            .visibility(this.item.food_count > 0 ? Visibility.Visible : Visibility.Hidden)
        Text(this.item.food_count.toString()).TextStyle()
          .visibility(this.item.food_count > 0 ? Visibility.Visible : Visibility.Hidden)
        Text('+').AddTextStyle()
          .onClick(() => {
            this.item.food_count++
          })
      }.layoutWeight(1)
    }
    .height(40)
    .width('100%')
  }
}

interface FoodInfo { // 接口:1、不能给初始值 2、用接口声明类型
  order_id:number
  food_name:string
  food_price:number
  food_count:number
}

// observe监听的是class的变化,当class中的某一项值变化,就会触发当前ui的更新
// 食品类
@Observed // 使用observe修饰带构造函数的类
class FoodObjectClass implements FoodInfo {
  // implements代表继承实现的意思,继承接口中的属性
  order_id = 0  // class中的属性必须给初始值,属性类型可以去掉
  food_name:  string = ""
  food_price: number = 0
  food_count: number = 0
  constructor(obj:FoodInfo) {
    this.order_id = obj.order_id
    this.food_name = obj.food_name
    this.food_price = obj.food_price
    this.food_count = obj.food_count
  }
}

@Component
struct BottonCard {
  @Link
  myList:FoodObjectClass[]
  build() {
    Button('更改菜品的数量')
      .onClick(() => {
        // map循环数组返回新数组,map中item代表数组中的元素,map会将其中的item组成一个新的数组
        this.myList = this.myList.map(item => {
          item.food_count++
          return item
        })
      })
  }
}

  上述代码中,我们用了interface,interface声明类型不需要给初始值,class声明类型必须给初始值(下一代要求)
● 我们使用Class继承实现了interface,并且通过传入的对象将我们Class中的属性进行赋值
● 使用了Observed这个装饰器来修饰class,那么只要我们改动class的属性,它就会驱动UI的更新(只是第一层)
  注意: 只有Observed修饰的class才可以被 ObjectLink使用,并且Entry修饰的组件不允许使用ObjectLink

上一篇 下一篇

猜你喜欢

热点阅读