06.HarmonyOS-状态管理

1.State


class Person {
  name: string
  age: number
  money: number

  //参加加问号为可选参数
  constructor(name: string, age: number, money?: number) {
    this.name = name
    this.age = age
    this.money = money
  }
}

@Extend(Text) function styleText(){
  .margin({ top: 10 })
  .backgroundColor("#ccc")
  .padding({ top: 5, bottom: 5, left: 10, right: 10 })
  .fontWeight(FontWeight.Bold)
  .border({ width: 10, color: "#ccc", radius: 5 })
}

@Entry
@Component
struct StatePage {
  @State name: string = "Tom"
  @State age: number = 1
  @State jack:Person=new Person("Jack",5,1000000)
  @State rose:Person=new Person("Jack",5)

  build() {
    Column(){
      Text(`姓名:${this.name} ,年龄: ${this.age}`)
        .onClick(() => {
          this.age++
          this.name = "Tom"
        })
        .styleText()

      Text(`姓名:${this.jack.name} ,年龄: ${this.jack.age} ,月薪: ${this.jack.money}`)
        .onClick(() => {
          this.jack.age++
          this.jack.money++
          this.jack.name = "Jack" ;
        })
        .styleText()


      Text(`姓名:${this.rose.name} ,年龄: ${this.rose.age} ,月薪: ${this.rose.money}`)
        .onClick(() => {
          this.rose.age++
          this.rose.name = "Jack" ;
        })
        .styleText()
    }
    .justifyContent(FlexAlign.Center)
    .width("100%")
  }
}

2.Prop、Link



//任务类
class Task {
  static id: number = 1
  //任务名称
  name: string = `任务${Task.id++}`
  //任务状态,是否完成
  finished: boolean = false
}

//统一卡片样式
@Styles function card() {
  .width("90%")
  .padding(20)
  .backgroundColor(Color.White)
  .borderRadius(15)
  .shadow({ radius: 6, color: "#1f000000", offsetX: 2, offsetY: 4 })
}

//任务完成样式
@Extend(Text) function finishedTask() {
  .decoration({ type: TextDecorationType.LineThrough })
  .fontColor("#B1B2B1")
}

@Entry
@Component
struct PropPage {
  //总任务数量
  @State totalTask: number = 0
  //已完成任务数量
  @State finishTask: number = 0
  //任务数组
  @State tasks: Task[] = []



  build() {
    Column({ space: 10 }) {
      //1.任务进度卡片
      TaskStatistics({totalTask:this.totalTask,finishTask:this.finishTask})
      //2.新增任务按钮
      //3.任务列表
      //传引用使用$totalTask
      TaskList({totalTask:$totalTask,finishTask:$finishTask,tasks:$tasks})


    }
    .backgroundColor("#f1f2f3")

  }



}


//1.任务进度卡片
@Component
struct TaskStatistics{
  //@Prop单项同步父复制一份给子组件,子组件修改不会影响父组件,不能初始化
  @Prop finishTask: number
  @Prop totalTask: number
  build() {
    Row() {
      Text("任务进度")
        .fontSize(30)
        .fontWeight(FontWeight.Bold)

      //堆叠容器,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件。
      Stack() {
        //进度条组件,用于显示内容加载或操作处理等进度。
        Progress({ value: this.finishTask, total: this.totalTask, type: ProgressType.Ring })
          .width(100)

        //使用Row为了让两个Text组件不要分这么开
        Row() {
          Text(this.finishTask.toString())
            .fontSize(24)
            .fontColor("#66D")
          Text(" / " + this.totalTask.toString())
            .fontSize(24)
        }

      }

    }
    .card()
    .margin({ top: 20, bottom: 10 })
    .justifyContent(FlexAlign.SpaceEvenly)
  }
}

//2.新增任务按钮
//3.任务列表
@Component
struct TaskList{
  //@Link双向同步传递的为地址,子组件修改父组件也跟着修改,不能初始化赋值
  //总任务数量
  @Link totalTask: number
  //已完成任务数量
  @Link finishTask: number
  //任务数组
  @Link tasks: Task[]

  build() {

    //子元素只能有一个根元素,所以需要放到一个容器里面去
    Column(){
      //2.新增任务按钮
      Button("新增任务")
        .width(200)
        .onClick(() => {
          //新增任务数据
          this.tasks.push(new Task())
          //更新任务总数
          this.handleTaskChange()
        })


      //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%")
      .padding({ top: 10 })
      //高度其他元素(默认为0)占用完,剩下的都给我
      .layoutWeight(1)
      //内部元素居中
      .alignListItem(ListItemAlign.Center)
    }


  }




  @Builder DeleteButton(index: number) {
    Button("删除")
      .backgroundColor(Color.Red)
      .margin({ left: 5 })
      .onClick(() => {
        //删除数组
        this.tasks.splice(index, 1)
        //更新总数和完成任务
        this.handleTaskChange()
      })
  }

  //更新总数和完成任务
  handleTaskChange() {
    //更新任务总数
    this.totalTask = this.tasks.length
    //筛选选择的任务
    this.finishTask = this.tasks.filter((item) => {
      return item.finished
    }).length
  }



}

3.Provide、Consume


//任务类
class Task {
  static id: number = 1
  //任务名称
  name: string = `任务${Task.id++}`
  //任务状态,是否完成
  finished: boolean = false
}

//统一卡片样式
@Styles function card() {
  .width("90%")
  .padding(20)
  .backgroundColor(Color.White)
  .borderRadius(15)
  .shadow({ radius: 6, color: "#1f000000", offsetX: 2, offsetY: 4 })
}

//任务完成样式
@Extend(Text) function finishedTask() {
  .decoration({ type: TextDecorationType.LineThrough })
  .fontColor("#B1B2B1")
}

class StateInfo{
  //总任务数量
  totalTask: number = 0
  //已完成任务数量
  finishTask: number = 0
  //任务数组
  tasks: Task[] = []
}

@Entry
@Component
struct PropPage {

  @Provide info: StateInfo = new StateInfo()


  build() {
    Column({ space: 10 }) {
      //1.任务进度卡片
      TaskStatistics()
      //2.新增任务按钮
      //3.任务列表
      //传引用使用$totalTask
      TaskList()


    }
    .backgroundColor("#f1f2f3")

  }



}


//1.任务进度卡片
@Component
struct TaskStatistics{
  //@Provide、@Consume可以跨组件使用不用传值
  @Consume info: StateInfo
  build() {
    Row() {
      Text("任务进度")
        .fontSize(30)
        .fontWeight(FontWeight.Bold)

      //堆叠容器,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件。
      Stack() {
        //进度条组件,用于显示内容加载或操作处理等进度。
        Progress({ value: this.info.finishTask, total: this.info.totalTask, type: ProgressType.Ring })
          .width(100)

        //使用Row为了让两个Text组件不要分这么开
        Row() {
          Text(this.info.finishTask.toString())
            .fontSize(24)
            .fontColor("#66D")
          Text(" / " + this.info.totalTask.toString())
            .fontSize(24)
        }

      }

    }
    .card()
    .margin({ top: 20, bottom: 10 })
    .justifyContent(FlexAlign.SpaceEvenly)
  }
}

//2.新增任务按钮
//3.任务列表
@Component
struct TaskList{
  //@Provide、@Consume可以跨组件使用不用传值
  @Consume info: StateInfo

  build() {

    //子元素只能有一个根元素,所以需要放到一个容器里面去
    Column(){
      //2.新增任务按钮
      Button("新增任务")
        .width(200)
        .onClick(() => {
          //新增任务数据
          this.info.tasks.push(new Task())
          //更新任务总数
          this.handleTaskChange()
        })


      //3.任务列表
      List({ space: 10 }) {
        ForEach(
          this.info.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%")
      .padding({ top: 10 })
      //高度其他元素(默认为0)占用完,剩下的都给我
      .layoutWeight(1)
      //内部元素居中
      .alignListItem(ListItemAlign.Center)
    }


  }




  @Builder DeleteButton(index: number) {
    Button("删除")
      .backgroundColor(Color.Red)
      .margin({ left: 5 })
      .onClick(() => {
        //删除数组
        this.info.tasks.splice(index, 1)
        //更新总数和完成任务
        this.handleTaskChange()
      })
  }

  //更新总数和完成任务
  handleTaskChange() {
    //更新任务总数
    this.info.totalTask = this.info.tasks.length
    //筛选选择的任务
    this.info.finishTask = this.info.tasks.filter((item) => {
      return item.finished
    }).length
  }



}

4.ObjectLink、Observed



//任务类
//对象嵌套对象时,修改里面的对象页面不会渲染,所以需要@Observed标注在嵌套对象上@ObjectLink标注在使用的对象上,就可以正常渲染
@Observed
class Task {
  static id: number = 1
  //任务名称
  name: string = `任务${Task.id++}`
  //任务状态,是否完成
  finished: boolean = false
}

//统一卡片样式
@Styles function card() {
  .width("90%")
  .padding(20)
  .backgroundColor(Color.White)
  .borderRadius(15)
  .shadow({ radius: 6, color: "#1f000000", offsetX: 2, offsetY: 4 })
}

//任务完成样式
@Extend(Text) function finishedTask() {
  .decoration({ type: TextDecorationType.LineThrough })
  .fontColor("#B1B2B1")
}

class StateInfo{
  //总任务数量
  totalTask: number = 0
  //已完成任务数量
  finishTask: number = 0
  //任务数组
  tasks: Task[] = []
}

@Entry
@Component
struct PropPage {

  @Provide info: StateInfo = new StateInfo()


  build() {
    Column({ space: 10 }) {
      //1.任务进度卡片
      TaskStatistics()
      //2.新增任务按钮
      //3.任务列表
      //传引用使用$totalTask
      TaskList()

    }
    .backgroundColor("#f1f2f3")

  }



}


//1.任务进度卡片
@Component
struct TaskStatistics{
  //@Provide、@Consume可以跨组件使用不用传值
  @Consume info: StateInfo
  build() {
    Row() {
      Text("任务进度")
        .fontSize(30)
        .fontWeight(FontWeight.Bold)

      //堆叠容器,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件。
      Stack() {
        //进度条组件,用于显示内容加载或操作处理等进度。
        Progress({ value: this.info.finishTask, total: this.info.totalTask, type: ProgressType.Ring })
          .width(100)

        //使用Row为了让两个Text组件不要分这么开
        Row() {
          Text(this.info.finishTask.toString())
            .fontSize(24)
            .fontColor("#66D")
          Text(" / " + this.info.totalTask.toString())
            .fontSize(24)
        }

      }

    }
    .card()
    .margin({ top: 20, bottom: 10 })
    .justifyContent(FlexAlign.SpaceEvenly)
  }
}

//2.新增任务按钮
//3.任务列表
@Component
struct TaskList{
  //@Provide、@Consume可以跨组件使用不用传值
  @Consume info: StateInfo

  build() {

    //子元素只能有一个根元素,所以需要放到一个容器里面去
    Column(){
      //2.新增任务按钮
      Button("新增任务")
        .width(200)
        .onClick(() => {
          //新增任务数据
          this.info.tasks.push(new Task())
          //更新任务总数
          this.handleTaskChange()
        })

      //3.任务列表
      List({ space: 10 }) {
        ForEach(
          this.info.tasks,
          (item: Task, index) => {
            ListItem() {
              //方法传递时,方法里面有this关键字所以需要bind(this)把父类的绑定上去,不然就会使用子的this
              TaskItem({item:item,onTaskChange:this.handleTaskChange.bind(this)})
            }
            .swipeAction({ end: this.DeleteButton(index) })
          }
        )
      }
      .width("100%")
      .padding({ top: 10 })
      //高度其他元素(默认为0)占用完,剩下的都给我
      .layoutWeight(1)
      //内部元素居中
      .alignListItem(ListItemAlign.Center)
    }


  }




  @Builder DeleteButton(index: number) {
    Button("删除")
      .backgroundColor(Color.Red)
      .margin({ left: 5 })
      .onClick(() => {
        //删除数组
        this.info.tasks.splice(index, 1)
        //更新总数和完成任务
        this.handleTaskChange()
      })
  }

  //更新总数和完成任务
  handleTaskChange() {
    //更新任务总数
    this.info.totalTask = this.info.tasks.length
    //筛选选择的任务
    this.info.finishTask = this.info.tasks.filter((item) => {
      return item.finished
    }).length
  }



}

@Component
struct  TaskItem{
  //默认不能渲染数组里面的Task对象,使用@ObjectLink可以渲染嵌套对象
  @ObjectLink item: Task
  //方法传递
  onTaskChange:()=> void
  build() {
    Row() {
      //判断是否完成任务然后动态渲染
      if(this.item.finished){
        Text(this.item.name)
          .finishedTask()
      }else{
        Text(this.item.name)
          .fontSize(20)
      }

      Checkbox()
        .select(this.item.finished)
        .onChange((val) => {
          //多选框改变赋值给任务完成状态
          this.item.finished = val
          //筛选选择的任务
          //调用不到handleTaskChange方法,使用方法传递的方式调用
          //this.handleTaskChange()
          this.onTaskChange();
        })
    }
    .card()
    .justifyContent(FlexAlign.SpaceBetween)
  }
}




























(1)