赞
踩
当父子组件之间需要数据同步的时候,可以使用@Prop和@Link装饰器。
实现的案例之中,代码时平铺直叙的,阅读性可理解性比较差。我们应改遵循组件化开发的思想。
在我们使用组件开发的时候,遇到数据同步问题的时候,@State状态是解决不了的。所以就要用到@Prop和@Link
我们可以将任务进度卡片封装为一个组件、将任务按钮和卡片列表封装为另外一个组件,来实现组件化的目的。
我们先用@State尝试着封装任务进度卡片组件,然后再入口函数中使用。
- @Component
- struct TaskStatistics {
- @State finishTask: number = 0
- @State totalTask: number = 0
- build(){
- Row(){
- Text("任务进度")
- .fontSize(30)
- .fontWeight(FontWeight.Bold)
- Stack(){
- Progress({
- value:this.finishTask,
- total:this.totalTask,
- type:ProgressType.Ring
- })
- .width(100)
- Row(){
- Text(this.finishTask.toString())
- .fontSize(24)
- .fontColor('#36d')
- Text(' / ' +this.totalTask.toString())
- .fontSize(24)
- }
- }
- }
- .card()
- .margin({top:20,bottom:10})
- .justifyContent(FlexAlign.SpaceEvenly)
- }
- }
这样一来 PropPage组件就是父组件、TaskStatistics就是子组件。
其中的任务数量是由PropPage来维护的。所以我们需要从父亲向子传递数量属性,这时候我们会发现报错了,提示@State不支持之类的。
这说明再父子传值的时候,@State状态已经不支持了。我们这个时候可以使用Prop和Link两个装时期。
@Prop | @Link | |
同步类型 | 单向同步 | 双向同步 |
允许装饰的变量类型 | 1.@Prop只支持string、number、boolean、enum类型 2.父组件对象类型、子组件对象属性 3.不可以是数组、any | 1.父子类型一致:string、number、boolean、enum、object、class,以及他们的数组 2.数组中元素增、删、替换会引起刷新 3.嵌套类型以及数组中的对象属性无法触发视图更新。 |
初始化方式 | 不允许子组件初始化 | 父组件传递,禁止子组件初始化 |
@Prop是单向同步,父组件的改变会立即传递给子组件,但是子组件的修改不会影响父组件,他传递的是拷贝的值。
@LInk是双向同步,传递的是变量的引用,父亲和儿子使用的是一个变量,所以两方都会感知到变量的改变。
在封装任务列表的时候,要注意一些问题,比如说build函数下不能放入多个顶层,所以我们加一个Column容器,我们将按钮函数也加入。因为任务列表同任务进度是同步更新数据的,这里我们使用Link状态来完成。
- @Component
- struct TaskList {
- // 任务数量
- @State tasks: Task[] = []
- // 完成任务列表
- @Link finishTask: number
- // 所有的任务列表
- @Link totalTask: number
- // 通过过滤方法 更新已完成的任务数量
- handleTaskChange(){
- // 更新任务总数量
- this.totalTask = this.tasks.length
- // 已经完成的任务数量
- this.finishTask = this.tasks.filter(item => item.finished).length
- }
- build(){
- Column(){
- // 2.新增任务按钮
- Button('新增任务')
- .width(200)
- .onClick(()=>{
- // 1.新增任务
- this.tasks.push(new Task())
- // 2.更新任务数组
- this.totalTask = this.tasks.length
- })
- // 3.卡片列表
- List({space:10}){
- ForEach(
- this.tasks,
- (item: Task,index)=>{
- ListItem(){
- Row(){
- Text(item.name)
- .fontSize(20)
- Checkbox()
- .select(item.finished)
- .onChange(val=>{
- item.finished = val
- // 通过过滤方法 更新已完成的任务数量
- this.handleTaskChange()
- })
- }
- .card()
- .justifyContent(FlexAlign.SpaceBetween)
- }
- .swipeAction({end:this.DeleteButton(index)})
- }
- )
- }
- .width('100%')
- .layoutWeight(1)
- .alignListItem(ListItemAlign.Center)
- }
- }
- @Builder DeleteButton(index: number){
- Button("删除")
- .onClick(()=>{
- this.tasks.splice(index,1)
- this.handleTaskChange()
- })
- }
-
- }
我们在使用Link的时候,父类里面穿参数,需要使用$语法。
我们会发现效果与我们最开始的效果是一样一样的。
我们来验证一下@Prop和@Link的数据类型
我们来验证是否支持对象属性
- // 任务统计信息
- class StaticInfo{
- totalTask: number = 0
- finishTask: number = 0
- }
父组件中直接实例化 传值直接传入属性
我们在组件中使用对象属性来完成
- struct TaskList {
- // 任务数量
- @State tasks: Task[] = []
- @Link stat: StaticInfo
- // 通过过滤方法 更新已完成的任务数量
- handleTaskChange(){
- // 更新任务总数量
- this.stat.totalTask = this.tasks.length
- // 已经完成的任务数量
- this.stat.finishTask = this.tasks.filter(item => item.finished).length
- }
@Provide和@Consume可以跨组件提供类似@State和@Link的双向同步功能。
@Provide和@Consume内部就能传递信息,不需要手写传递。
我们可以直接使用provide和consume,参数就不需要传递了,内部帮忙维护,代价是资源的损耗。所以我们在使用的时候优先考虑@State和@Link状态,遇到跨组件的时候,在使用@Provide和@Consume。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。