鸿蒙系列--装饰器

news2024/9/21 4:26:09

一、基础UI组件结构

        每个UI组件需要定义为@Component struct对象,其内部必须包含一个且只能包含一个build(){}函数,用于绘制UI;struct之内、build()函数之外的地方用于存放数据。

二、基本UI装饰器

@Entry

装饰struct,页面的入口

@Component

装饰struct,表示该struct具有基于组件的能力

@Entry
@Component
struct TestPage {
    build() {
       ……
    }
}

三、数据装饰器

@State 父子相互独立

  • 装饰的变量是组件的局部变量,必须本地初始化,可通过构造参数赋值
  • 当该数据被修改时,所在组件的build()方法会被重新调用,会重新绘制所在UI
子组价:
@Component
export struct ComponentPage {
  @State count: number = 0

  private toggleClick() {
    this.count += 1
  }

  build() {
    Row() {
      Column({ space: 20 }) {
        Button(`这是子组件,${this.count}`)
          .fontSize(24)
          .onClick(this.toggleClick.bind(this))
      }
      .width('100%')
    }
  }
}
父组件:
import { ComponentPage } from "./ComponentPage"

@Entry
@Component
struct StatePage {
  @State count: number = 0

  private toggleClick() {
    this.count += 1
  }

  build() {
    Row() {
      Column({ space: 20 }) {
        Button(`这是父组件,当前值: ${this.count}`)
          .fontSize(24)
          .onClick(this.toggleClick.bind(this))

        //使用默认初始化值
        ComponentPage()
        //设置count初始值为:20
        ComponentPage({ count: 20 })
      }
      .width('100%')
    }.height('100%')
  }
}
描述:
  • 当被点击之后修改了count的值,页面会重新绘制UI
  • 子组件中的count和父组件的count互不影响
  • 可以给子组件构造方法设置初始值
  • 使用@State修饰的变量必须初始化
效果图:

@Prop 父子单向同步

  • 继承@State的所有功能
  • 被其装饰的变量可以和父组件建立单向同步关系。@Prop装饰的变量是可变的,但修改不会同步回父组件,当父组件的@State变化时,本地修改的@Prop会被覆盖
子组件:
@Component
export struct ComponentPage {
  @Prop count: number

  private toggleClick() {
    this.count += 1
  }

  build() {
    Row() {
      Column({ space: 20 }) {
        Button(`这是子组件,${this.count}`)
          .fontSize(24)
          .onClick(this.toggleClick.bind(this))
      }
      .width('100%')
    }
  }
}
父组件:
import { ComponentPage } from "./ComponentPage"

@Entry
@Component
struct StatePage {
  @State count: number = 0

  private toggleClick() {
    this.count += 1
  }

  build() {
    Row() {
      Column({ space: 20 }) {
        Button(`这是父组件,当前值: ${this.count}`)
          .fontSize(24)
          .onClick(this.toggleClick.bind(this))

        ComponentPage({ count: this.count })
      }
      .width('100%')
    }.height('100%')
  }
}
描述:
  • 将父组件的count设置到子组件使用的@Prop修饰的变量时,父组件与子组件这时建立起单向同步
  • 父组件修改值后,子组件跟着修改,子组件修改值父组件不受影响
  • 使用的@Prop修饰的变量不能自己初始化
效果图:

@Link 父子双向同步

  • @Link装饰的变量和父组件构建双向同步关系的状态变量,父组件会接受来自@Link装饰的变量的修改的同步,父组件的更新也会同步给@Link装饰的变量。
  • @Link装饰的变量与其父组件中的数据源共享相同的值
  • @Link装饰器不能在@Entry装饰的自定义组件中使用
子组件:
@Component
export struct ComponentPage {
  @Link count: number

  private toggleClick() {
    this.count += 1
  }

  build() {
    Row() {
      Column({ space: 20 }) {
        Button(`这是子组件,${this.count}`)
          .fontSize(24)
          .onClick(this.toggleClick.bind(this))
      }
      .width('100%')
    }
  }
}
父组件:
import { ComponentPage } from "./ComponentPage"

@Entry
@Component
struct StatePage {
  @State count: number = 0

  private toggleClick() {
    this.count += 1
  }

  build() {
    Row() {
      Column({ space: 20 }) {
        Button(`这是父组件,当前值: ${this.count}`)
          .fontSize(24)
          .onClick(this.toggleClick.bind(this))

        ComponentPage({ count: $count })
      }
      .width('100%')
    }.height('100%')
  }
}
描述:
  • 父组件通过$count来和子组件的@Link修饰的值绑定
  • 绑定之后实现父子双向绑定,修改一端,另一组件也随之变化
  • 使用@Link不能自己初始化
效果图:

@State、@Prop与@Link的异同

相同点:

  • 都会引起UI重绘
  • 内部私有

不同点:

不同点@State@Prop@Link
装饰内容基本数据类型,类,数组基本数据类型基本数据类型,类,数组
关联不与其他控件关联父@State -> 子@Prop 单向关联父@State <-> 子@Link 双向关联
初始化时机声明时创建组件时由参数传入创建组件时由参数传入

四、生产消费的装饰器

@Provide、@Consume

后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递

案例:

在父组件中将数据多级传递给子组件,子子组件

1.使用@Link修饰的变量进行传递
父组件:
import { ProviderSonPage } from "./ProviderSonPage"

@Entry
@Component
struct ProviderPage {
  @State message: string = '父类A'

  build() {
    Row() {
      Column() {
        Text(this.message).fontSize(50).fontColor(Color.Red)
          .onClick(() => {
            //点击文字  进行切换
            this.message = this.message === '父类A' ? '父类B' : '父类A'
          })
        //调用子组件
        ProviderSonPage({ sonMsg: $message })
      }
      .width('100%')
    }
    .height('100%')
  }
}
子组件:
import { ProviderGrandSonPage } from "./ProviderGrandSonPage"

@Component
export struct ProviderSonPage {
  @Link sonMsg: string

  build() {
    Column() {
      Text(this.sonMsg).fontSize(30).fontColor(Color.Green)
        .onClick(() => {
          this.sonMsg = '我是子类'
        })
      //调用孙子组件:子类的子类
      ProviderGrandSonPage({ grandSonMsg: $sonMsg })
    }
  }
}
子子组件:
@Component
export struct ProviderGrandSonPage {
  @Link grandSonMsg: string

  build() {
    Column() {
      Text(this.grandSonMsg).fontSize(20).fontColor(Color.Blue)
        .onClick(() => {
          this.grandSonMsg = '我是子类的子类'
        })
    }
  }
}
总结:
  • 都需要通过一个多余被@Link修饰的变量进行传递,太过复杂,如果传递层级太深没更加明显
2.发布者订阅者模式

使用发布者Provide和订阅者Consume可以直接传递到子子组件

父组件:
import { ProviderSonPage } from "./ProviderSonPage"

@Entry
@Component
struct ProviderPage {
  @Provide('Mes') message: string = '父类A'
  //也可以写成@Provide message: string = '父类A'
  build() {
    Row() {
      Column() {
        Text(this.message).fontSize(50).fontColor(Color.Red)
          .onClick(() => {

            this.message = this.message === '父类A' ? '父类B' : '父类A'
          })
        //调用子组件时就不再需要传递参数
        ProviderSonPage()
      }
      .width('100%')
    }
    .height('100%')
  }
}
子组件:
import { ProviderGrandSonPage } from "./ProviderGrandSonPage"

@Component
export struct ProviderSonPage {
  @Consume('Mes') sonMsg:string

  build() {
    Column() {
      Text(this.sonMsg).fontSize(30).fontColor(Color.Green)
        .onClick(() => {
          this.sonMsg = '我是子类'
        })
      //调用子组件时就不再需要传递参数
      ProviderGrandSonPage()
    }
  }
}
子子组件:
@Component
export struct ProviderGrandSonPage {
  @Consume('Mes') grandSonMsg:string
  //也可以写成@Consume message:string

  build() {
    Column() {
      Text(this.grandSonMsg).fontSize(20).fontColor(Color.Blue)
        .onClick(() => {
          this.grandSonMsg = '我是子类的子类'
        })
    }
  }
}
总结:
  • 使用发布者订阅者模式,父类使用@Provide,其他需要观察的子类使用@Consume,就可以能实现双向绑定
  • 当层级很深时不需要一层一层的往下传递,直接使用发布者订阅者进行监听就能实现相同的效果
  • @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,变量类型必须相同
  • @Provide必须设置初始值,@Consume不可设置默认初始值
  • @Provide修饰的变量和@Consume修饰的变量是一对多的关系

效果图:

五、状态变量更改通知

@Watch:使用观察者模式的装饰器,但该装饰器不是触发变量变化,而是绑定一个函数,当@Watch变量变化时,调用该函数

@Watch和自定义组件更新

子组件:
@Component
export struct TotalViewPage {
  @Prop @Watch('onCountUpdated') count: number;
  @State total: number = 0;
  // @Watch 回调
  onCountUpdated(propName: string): void {
    this.total += this.count;
  }

  build() {
    Text(`Total: ${this.total}`)
  }
}
父组件:
import {TotalViewPage} from "./TotalViewPage"

@Entry
@Component
struct CountModifierPage {
  @State count: number = 0;

  build() {
    Column() {
      Button('add to basket')
        .onClick(() => {
          this.count++
        })
      TotalViewPage({ count: this.count })
    }
  }
}
描述:
  1. CountModifier自定义组件的Button.onClick点击事件自增count
  2. 由于@State count变量更改,子组件TotalView中的@Prop被更新,其@Watch('onCountUpdated')方法被调用,更新了子组件TotalView 中的total变量
  3. 子组件TotalView中的Text重新渲染

@Watch与@Link组合使用

bean对象:PurchaseItem
export class PurchaseItem {
  static NextId: number = 0;
  public id: number;
  public price: number;

  constructor(price: number) {
    this.id = PurchaseItem.NextId++;
    this.price = price;
  }
}
子类:BasketViewer
import {PurchaseItem} from "./PurchaseItem"

@Component
export struct BasketViewer {
  @Link @Watch('onBasketUpdated') shopBasket: PurchaseItem[];
  @State totalPurchase: number = 0;

  updateTotal(): number {
    let total = this.shopBasket.reduce((sum, i) => sum + i.price, 0);
    // 超过100欧元可享受折扣
    if (total >= 100) {
      total = 0.9 * total;
    }
    return total;
  }
  // @Watch 回调
  onBasketUpdated(propName: string): void {
    this.totalPurchase = this.updateTotal();
  }
  build() {
    Column() {
      ForEach(this.shopBasket,
        (item) => {
          Text(`Price: ${item.price.toFixed(2)} €`)
        },
        item => item.id.toString()
      )
      Text(`Total: ${this.totalPurchase.toFixed(2)} €`)
    }
  }
}
父类:BasketModifierPage
import {BasketViewer} from "./BasketViewer"
import {PurchaseItem} from "./PurchaseItem"

@Entry
@Component
struct BasketModifierPage {
  @State shopBasket: PurchaseItem[] = [];
  build() {
    Column() {
      Button('Add to basket')
        .onClick(() => {
          this.shopBasket.push(new PurchaseItem(Math.round(100 * Math.random())))
        })
      BasketViewer({ shopBasket: $shopBasket })
    }
  }
}
描述:
  1. BasketModifierPage组件的Button.onClick向BasketModifier shopBasket中添加条目
  2. @Link装饰的BasketViewer shopBasket值发生变化
  3. 状态管理框架调用@Watch函数BasketViewer onBasketUpdated 更新BasketViewer TotalPurchase的值
  4. @Link shopBasket的改变,新增了数组项,ForEach组件会执行item Builder,渲染构建新的Item项;@State totalPurchase改变,对应的Text组件也重新渲染
  5. 重新渲染是异步发生的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1354369.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[足式机器人]Part2 Dr. CAN学习笔记-自动控制原理Ch1-10奈奎斯特稳定性判据-Nyquist Stability Criterion

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-自动控制原理Ch1-10奈奎斯特稳定性判据-Nyquist Stability Criterion Cauchy’s Argument Priciple 柯西幅角原理 结论&#xff1a; s s s平面内顺时针画一条闭合曲线 A A A&#xff0c; B B B曲…

极狐GitLab Helm Chart 已上线,玩转云原生极狐GitLab!

极狐GitLab 研发团队提供了极狐GitLab & Runner 的 Helm Chart&#xff0c;方便用户在 Kubernetes 相关环境上来安装和运行极狐GitLab & Runner。Helm Chart 已经上线 Artifact Hub &#xff1a; 使用指南 只需简单两步就可以开启极狐GitLab & Runner Helm Chart …

【Week-P4】CNN猴痘病识别

文章目录 一、环境配置二、准备数据三、搭建网络结构四、开始训练五、查看训练结果六、总结2.3 ⭐torch.utils.data.DataLoader()参数详解6.1 print()常用的三种输出格式6.2 修改网络结构&#xff0c;观察训练结果6.2.1 增加pool2、conv6、bn6&#xff0c;test_accuracy82.5%6.…

postman使用-05新建测试集

文章目录 两种方式新建测试集测试集&#xff1a;允许用户以项目或模块的方式对多个接口进行分类和管理。每一个测试请求都可以被看作是一个独立的测试用例&#xff0c;而collections则可以同时管理多个测试用例的执行。方法一&#xff1a;点击左上角直接创建测试方法二&#xf…

ubuntu 执行apt-get update报错

系统是Ubuntu22.04 执行apt-get update 遇到如下情况 E: 无法下载 https://mirrors.tuna.tsinghua.edu.cn/ubuntu/dists/jammy/main/binary-arm64/Packages 404 Not Found [IP: 101.6.15.130 443] E: 无法下载 https://mirrors.tuna.tsinghua.edu.cn/ubuntu/dists/jammy-upda…

通灵术揭秘:空碗“竖筷子”不倒

通灵术揭秘&#xff1a;空碗“竖筷子”不倒 释名&#xff1a;竖筷子是流传很广的一种民间小术&#xff0c;因其法是在碗中竖起一支或三支筷子&#xff0c;故名。 用处&#xff1a;如果有人莫名其妙的生病了&#xff0c;医药无效&#xff0c;按民间的说法&#xff0c;就是遇鬼了…

Spark二、Spark技术栈之Spark Core

Spark Core spark核心&#xff1a;包括RDD、RDD算子、RDD的持久化/缓存、累加器和广播变量 学习链接&#xff1a;https://mp.weixin.qq.com/s/caCk3mM5iXy0FaXCLkDwYQ 一、 RDD 1.1 为什么要有RDD 在许多迭代式算法(比如机器学习、图算法等)和交互式数据挖掘中&#xff0c;…

基于SSM的校园快递管理系统

目录 前言 开发环境以及工具 项目功能介绍 学生&#xff1a; 管理员&#xff1a; 详细设计 获取源码 前言 本项目是一个基于IDEA和Java语言开发的基于SSM的校园快递管理系统应用。应用包含学生端和管理员端等多个功能模块。 欢迎使用我们的校园快递管理系统&#xff01;我…

清风数学建模笔记-多分类-fisher线性判别分析

内容&#xff1a;Fisher线性判别分析 一.介绍&#xff1a; 1.给定的训练姐&#xff0c;设法投影到一维的直线上&#xff0c;使得同类样例的投影点尽可能接近和密集&#xff0c;异类投影点尽可能远离。 2.如何同类尽可能接近&#xff1a;方差越小 3.如何异类尽可能远离&#…

如何将Docker中的Tomact彻底删除

目录 前言&#xff1a; 一.删除Tomcat容器 列出所有在运行的容器信息 ​编辑 如果tomcat容器正在运行先停止&#xff0c;可以通过容器id或者容器名称 再次查看容器运行情况&#xff0c;可以看到没有运行中的容器了. 查看所有容器&#xff08;-a表示查看所有&#xff09;无…

MySQL取出N列里最大or最小的一个数据

如题&#xff0c;现在有3列&#xff0c;都是数字类型&#xff0c;要取出这3列里最大或最小的的一个数字 -- N列取最小 SELECT LEAST(temperature_a,temperature_b,temperature_c) min FROM infrared_heat-- N列取最大 SELECT GREATEST(temperature_a,temperature_b,temperat…

Basis Pursuit ADMM

c笔记 ref. distr_opt_stat_learning_admm.html Basis pursuit is the equality-constrained minimization problem In ADMM form, basis pursuit can be written as The ADMM algorithm is then The x-update, which involves solving a linearly-constrained minimu…

Vue v-html中内容图片过大自适应处理

之前图片如下&#xff0c;图片已经超出了页面的展示范围 对v-html增加样式处理 <div class"body padding-l scroll " v-html"docData.content"> </div><style scoped>.body >>> img {max-width: 100% ;} </style>…

XYZ世代

Z世代&#xff0c;Gen Zers&#xff0c;Generation Z &#xff0c;一词最早出现于欧美地区&#xff0c;是美国及欧洲的流行用语&#xff0c;泛指在1995-2009年间出生的一代人&#xff0c;千禧后一代。又称网络世代、互联网世代&#xff0c;网生代&#xff0c;二次元世代&#x…

【第一期】操作系统期末大揭秘:知识回顾与重点整理

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 操作系统概述1.1 操作系统定义1.2 操作系统的作用1.3 操作系统的功能1.4 操作…

机器人制作开源方案 | 核酸检测辅助机器人

作者&#xff1a;周文亚、胡冲、王晓强、张娟 单位&#xff1a;北方民族大学 指导老师&#xff1a;马行、穆春阳 1. 场景调研 新型冠状病毒肺炎全球流行已近三年&#xff0c;其变异毒株不断增强的传播力同时其症状不断变轻&#xff0c;其中无症状&#xff08;怎么确认是否被…

EM算法公式详细推导

EM算法是什么&#xff1f; EM算法是一种迭代算法&#xff0c;用于含隐变量概率模型参数的极大似然估计&#xff0c;或极大后验概率估计。EM算法由两步组成&#xff1a;E步&#xff0c;求期望&#xff1b;M步&#xff1a;求极大。EM算法的优点是简单性和普适性。 符号说明&…

QT基础知识

QT基础知识 文章目录 QT基础知识1、QT是什么2、Qt的发展史3、为什么学习QT4、怎么学习QT1、工程的创建(环境的下载与安装请百度&#xff09;2、创建的工程结构说明3、怎么看帮助文档1、类使用的相关介绍2. 查看所用部件&#xff08;类&#xff09;的相应成员函数&#xff08;功…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于碳捕集与封存-电转气-电解熔融盐协同的虚拟电厂优化调度》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主的专栏栏目《论文与完整程序》 这个标题涉及到多个关键概念&#xff0c;让我们逐一解读&#xff1a; 碳捕集与封存&#xff08;Carbon Capture and Storage&#xff0c;CCS&#xff09;&a…

【Linux】常用的基本命令指令①

前言&#xff1a;从今天开始&#xff0c;我们逐步的学习Linux中的内容&#xff0c;和一些网络的基本概念&#xff0c;各位一起努力呐&#xff01; &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:数据结构 &#x1f448; &#x1f4af;代码…