当前位置: 首页 > article >正文

OpenHarmony 入门——ArkUI 自定义组件间的父子双向同步状态装饰器@Link语法(四)

文章大纲

  • 引言
  • 一、组件间状态装饰器@Link 父子双向同步
    • 1、使用规则
    • 2、支持的观察变化的场景和ArkUI 刷新UI
    • 3、@Link变量值初始化和更新机制
      • 3.1、初始渲染:执行父组件的build()函数后将创建子组件的新实例。
      • 3.2、@Link的数据源的更新:即父组件中状态变量更新,引起相关子组件的@Link的更新。
      • 3.2、@Link的更新
  • 二、@Link父子双向同步
    • 1、简单类型和类对象类型的@Link
    • 2、数组类型的@Link

引言

前一篇文章OpenHarmony 入门——ArkUI 自定义组件间父到子单向同步的装饰器@Prop语法(三) 介绍了父组件——>子组件数据同步的装饰器@Prop,今天介绍的是父<——>子双向同步的装饰器@Link.

一、组件间状态装饰器@Link 父子双向同步

父组件中@State, @StorageLink和@Link 和子组件@Link可以建立双向数据同步,@Link 的变量不用初始化。

@Link装饰器不能在@Entry装饰的自定义组件中使用。

1、使用规则

在这里插入图片描述

2、支持的观察变化的场景和ArkUI 刷新UI

  • 当装饰的数据类型为boolean、string、number类型时,可以同步观察到数值的变化。

  • 当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性。

  • 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化

  • 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。

  • 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。

  • 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。

3、@Link变量值初始化和更新机制

@Link装饰的变量和其所属的自定义组件共享生命周期。父组件和拥有@Link变量的子组件初始渲染和双向更新流程如下(以父组件为@State为例):

3.1、初始渲染:执行父组件的build()函数后将创建子组件的新实例。

初始化过程如下:

  • 必须指定父组件中的@State变量,用于初始化子组件的@Link变量。
  • 子组件的@Link变量值与其父组件的数据源变量保持同步(双向数据同步)。
    父组件的@State状态变量包装类通过构造函数传给子组件,子组件的@Link包装类拿到父组件的@State的状态变量后,将当前@Link包装类this指针注册给父组件的@State变量。

3.2、@Link的数据源的更新:即父组件中状态变量更新,引起相关子组件的@Link的更新。

处理步骤:

  • 通过初始渲染的步骤可知,子组件@Link包装类把当前this指针注册给父组件。
  • 父组件@State变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(比如@Link包装类)。
  • 通知@Link包装类更新后,子组件中所有依赖@Link状态变量的系统组件(elementId)都会被通知更新。以此实现父组件对子组件的状态数据同步。

3.2、@Link的更新

当子组件中@Link更新后,处理步骤如下(以父组件为@State为例):

  • @Link更新后,调用父组件的@State包装类的set方法,将更新后的数值同步回父组件。
  • 子组件@Link和父组件@State分别遍历依赖的系统组件,进行对应的UI的更新。以此实现子组件@Link同步回父组件@State。

二、@Link父子双向同步

父子双向同步,父组件中@State, @StorageLink和@Link 和子组件@Link可以建立双向数据同步

@Link 的变量不用初始化

1、简单类型和类对象类型的@Link

class GreenButtonState {
  width: number = 0;
  constructor(width: number) {
    this.width = width;
  }
}
@Component
struct GreenButton {
  @Link greenButtonState: GreenButtonState;
  build() {
    Button('更新Green @Link属性')
      .width(this.greenButtonState.width)
      .height(100.0)
      .backgroundColor('#00ff00')
      .onClick(() => {
        if (this.greenButtonState.width < 700) {
          // 更新@Link 修饰的class的属性,变化可以被观察到并同步到父组件
          this.greenButtonState.width += 125;
        } else {
          // 更新class,变化可以被观察到同步回父组件
          this.greenButtonState = new GreenButtonState(100);
        }
      })
  }
}
@Component
struct YellowButton {
  @Link yellowButtonState: number;
  build() {
    Button('更新子组件的Yellow @Link')
      .width(this.yellowButtonState)
      .height(120.0)
      .backgroundColor('#ffff00')
      .onClick(() => {
        // 子组件的简单类型可以同步回父组件
        this.yellowButtonState += 50.0;
      })
  }
}

@Entry
@Component
struct ShufflingContainer {
  @State greenButtonState: GreenButtonState = new GreenButtonState(300);
  @State yellowButtonProp: number = 100;
  build() {
    Column() {
      // 简单类型从父组件@State向子组件@Link数据同步
      Button('Parent View: Set@#State yellowButton')
        .onClick(() => {
          this.yellowButtonProp = (this.yellowButtonProp < 700) ? this.yellowButtonProp + 100 : 100;
        })
      Divider()
      // class类型从父组件@State向子组件@Link数据同步
      Button('Parent View: Set@State GreenButton')
        .onClick(() => {
          this.greenButtonState = new GreenButtonState(80);
          //this.greenButtonState.width = (this.greenButtonState.width < 700) ? this.greenButtonState.width + 100 : 100;
        })
      Divider()
      // class类型初始化@Link
      GreenButton({ greenButtonState: this.greenButtonState })
      // 简单类型初始化@Link
      YellowButton({ yellowButtonState: this.yellowButtonProp })
    }
  }
}

2、数组类型的@Link

@Component
struct Child2 {
  @Link items: number[];

  build() {
    Column() {
      Button(`Button1: push`).onClick(() => {
        this.items.push(this.items.length + 1);
      })
      Button(`Button2: replace whole item`).onClick(() => {
        this.items = [100, 200, 300];
      })
    }
  }
}

@Component
struct Parent {
  @State arr: number[] = [1, 2, 3];
  build() {
    Column() {
      Child2({ items: $arr })
      ForEach(this.arr,
        (item:number) => {
          Text(`${item}`)
        },
        (item:number) => item.toString()
      )
    }
  }
}

http://www.kler.cn/a/383589.html

相关文章:

  • 强化特种作业管理,筑牢安全生产防线
  • 基于Spring Boot的工商局商家管理系统
  • 深度学习之超分辨率算法——FRCNN
  • 鸿蒙开发:了解帧动画
  • C语言初阶【13】——打印一个数的每一位(递归和非递归实现)
  • 单片机:实现数码管动态显示(0~99999999)74hc138驱动(附带源码)
  • Java 文件操作与IO流
  • JavaAPI(1)
  • 鸿蒙开发:ArkUI Toggle 组件
  • 计算机网络-网络原理初识
  • yolo继续训练模型
  • 【Linux内存泄漏】自创pamp 内存快照比对定位内存泄漏【2024-11-07】
  • npm镜像的常用操作
  • 职场逆袭!学会管理上司,你也能成为职场赢家
  • C语言 | Leetcode C语言题解之第524题通过删除字母匹配到字典里最长单词
  • 代码随想录算法训练营第二十一天 | LeetCode93.复原IP地址、LeetCode78.子集、LeetCode90.子集II
  • RFID应急消防管控:科技与效率的完美结合
  • golang学习2
  • 轮播图【HTML+CSS+JavaScript】
  • ubuntu 之 压缩与解压缩(7zip,zip,tar.gz,rar...)
  • 从零开始学python 6(持续更新中ing)
  • 知识总结三
  • Webserver(4.3)TCP通信实现
  • 基于CNN-BiLSTM的时间序列数据预测,15个输入1个输出,可以更改数据集,MATLAB代码
  • V4L2 sub-devices 翻译
  • Python基础学习_01