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
网友评论