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

鸿蒙系列--装饰器

一、基础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 = 0private 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 = 0private toggleClick() {this.count += 1}build() {Row() {Column({ space: 20 }) {Button(`这是父组件,当前值: ${this.count}`).fontSize(24).onClick(this.toggleClick.bind(this))//使用默认初始化值ComponentPage()//设置count初始值为:20ComponentPage({ count: 20 })}.width('100%')}.height('100%')}
}
描述:
  • 当被点击之后修改了count的值,页面会重新绘制UI
  • 子组件中的count和父组件的count互不影响
  • 可以给子组件构造方法设置初始值
  • 使用@State修饰的变量必须初始化
效果图:

@Prop 父子单向同步

  • 继承@State的所有功能
  • 被其装饰的变量可以和父组件建立单向同步关系。@Prop装饰的变量是可变的,但修改不会同步回父组件,当父组件的@State变化时,本地修改的@Prop会被覆盖
子组件:
@Component
export struct ComponentPage {@Prop count: numberprivate 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 = 0private 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: numberprivate 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 = 0private 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: stringbuild() {Column() {Text(this.sonMsg).fontSize(30).fontColor(Color.Green).onClick(() => {this.sonMsg = '我是子类'})//调用孙子组件:子类的子类ProviderGrandSonPage({ grandSonMsg: $sonMsg })}}
}
子子组件:
@Component
export struct ProviderGrandSonPage {@Link grandSonMsg: stringbuild() {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:stringbuild() {Column() {Text(this.sonMsg).fontSize(30).fontColor(Color.Green).onClick(() => {this.sonMsg = '我是子类'})//调用子组件时就不再需要传递参数ProviderGrandSonPage()}}
}
子子组件:
@Component
export struct ProviderGrandSonPage {@Consume('Mes') grandSonMsg:string//也可以写成@Consume message:stringbuild() {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. 重新渲染是异步发生的

相关文章:

鸿蒙系列--装饰器

一、基础UI组件结构 每个UI组件需要定义为Component struct对象&#xff0c;其内部必须包含一个且只能包含一个build(){}函数&#xff0c;用于绘制UI&#xff1b;struct之内、build()函数之外的地方用于存放数据。 二、基本UI装饰器 Entry 装饰struct&#xff0c;页面的入口…...

FairGuard游戏加固产品常见问题解答

针对日常对接中&#xff0c;各位用户对FairGuard游戏加固方案在安全性、稳定性、易用性、接入流程等方面的关注&#xff0c;我们梳理了相关问题与解答&#xff0c;希望可以让您对产品有一个初步的认知与认可。 Q1:FairGuard游戏加固产品都有哪些功能? A&#xff1a;FairGuar…...

Redis(二)数据类型

文章目录 官网备注十大数据类型StringListHashSetZSetBitmapHyperLogLog&#xff1a;GEOStreamBitfield 官网 英文&#xff1a;https://redis.io/commands/ 中文&#xff1a;http://www.redis.cn/commands.html 备注 命令不区分大小写&#xff0c;key区分大小写帮助命令help…...

2023年广东省网络安全B模块(笔记详解)

模块B 网络安全事件响应、数字取证调查和应用安全 一、项目和任务描述: 假定你是某网络安全技术支持团队成员,某企业的服务器系统被黑客攻击,你的团队前来帮助企业进行调查并追踪本次网络攻击的源头,分析黑客的攻击方式,发现系统漏洞,提交网络安全事件响应报告,修复系统…...

每日力扣算法题(简单篇)

543.二叉树的直径 原题&#xff1a; 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 解题思路&#xff1a; …...

Flume基础知识(三):Flume 实战监控端口数据官方案例

1. 监控端口数据官方案例 1&#xff09;案例需求&#xff1a; 使用 Flume 监听一个端口&#xff0c;收集该端口数据&#xff0c;并打印到控制台。 2&#xff09;需求分析&#xff1a; 3&#xff09;实现步骤&#xff1a; &#xff08;1&#xff09;安装 netcat 工具 sudo yum …...

通过IP地址如何进行网络安全防护

IP地址在网络安全防护中起着至关重要的作用&#xff0c;可以用于监控、过滤和控制网络流量&#xff0c;识别潜在威胁并加强网络安全。以下是通过IP地址进行网络安全防护的一些建议&#xff1a; 1. 建立IP地址白名单和黑名单&#xff1a; 白名单&#xff1a;确保只有授权的IP地…...

Vue.js 中使用 Watch 选项实现动态问题判断与展示答案

组件结构 以下是组件的基本结构&#xff1a; <template><div><!-- 输入框&#xff0c;用于输入问题 --><p>提出一个是/否问题&#xff1a;<input v-model"question" :disabled"loading" /></p><!-- 显示答案 --&…...

python笔记-自用

2024/1/3# python用号实现字符串的拼接&#xff0c;非字符串不能拼接 from pymysql import Connection# 连接mysql数据库salary 100 name "wang"ans "%s" % salary name print(ans)x 1 y 2 sum "%s %s" % (x, y) print(sum)# %s字符串占…...

安克创新与火山引擎数智平台开展合作:数据分析降门槛 数据协同破边界

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 近日&#xff0c;消费电子品牌安克创新与火山引擎数智平台&#xff08;VeDI&#xff09;达成合作&#xff0c;双方将聚焦安克创新大数据平台的海量数据分析场景&…...

LDD学习笔记 -- Linux内核模块

LDD学习笔记 -- 内核模块 简介LKM类型Static Linux Kernel ModuleDynamic Linux Kernel ModuleLKM编写语法 syntax详细描述内核头文件用户空间头文件Module Initialization FunctionModule Cleanup FunctionKeyword & Tag宏 __init __exitLKM入口注册Module Metadate&#…...

springboot整合springbatch批处理

springboot整合springbatch实现批处理 简介项目搭建步骤 简介 项目搭建 参考博客【场景实战】Spring Boot Spring Batch 实现批处理任务&#xff0c;保姆级教程 步骤 1.建表 建表sql CREATE TABLE student (id int NOT NULL AUTO_INCREMENT,name varchar(100) NOT NULL C…...

答案解析——C语言—第2次作业:转义字符

本次作业的链接如下&#xff1a;C语言—第2次作业&#xff1a;转义字符 1.下面哪个不是C语言内置的数据类型&#xff1a; C char //字符数据类型short //短整型int //整形long //长整型long long //更长的整形float //单精度浮点数double //双精度浮点数 …...

HTML5-新增表单input属性

新增表单属性 form控件主要新增的属性: autocomplete 是否启用表单的自动完成功能&#xff0c;取值&#xff1a;on&#xff08;默认&#xff09;、off novalidate 提交表单时不进行校验&#xff0c;默认会进行表单校验 autocomplete属性 概念&#xff1a;autocomplete属性…...

css-、串联选择器和后代选择器的用法

& &表示嵌套的上一级&#xff0c;这是sass的语法&#xff0c;代表上一级选择器 .btn {&.primary {background-color: #007bff;color: #fff;} } 编译出来的结果是同一个元素&#xff0c;有两个类名&#xff0c;两个类名之间没有空格&#xff1a; .btn.primary {…...

nifi详细介绍--一款开箱即用、功能强大可靠,可用于处理和分发数据的大数据组件

目录 目录 一、引言 二、NiFi 的历史背景介绍 三、NiFi 是什么&#xff1f; 核心特性 应用领域 四、NIFI 入门 五 、NiFi 工作流程 六、实际应用场景 七、优势总结 一、引言 NiFi&#xff08;Apache NiFi&#xff09;&#xff0c;全名为“Niagara Files”&#xff0…...

K8S Dashboard登录Token过期问题处理

整体思路 用户访问一个页面&#xff0c;在该页面中设置一个超链接&#xff0c;点击跳转至K8S Dashboard&#xff1b;跳转后&#xff0c;使用剪贴板上已复制的Token粘贴到Dashboard页面中的输入框登录即可。 写个定时任务将Token复制到页面上&#xff0c;过期了重新再登…...

x-cmd pkg | trafilatura - 网络爬虫和搜索引擎优化工具

目录 简介首次用户技术特点竞品和相关作品进一步阅读 简介 trafilatura 是一个用于从网页上提取文本的命令行工具和 python 包: 提供网络爬虫、下载、抓取以及提取主要文本、元数据和评论等功能可帮助网站导航和从站点地图和提要中提取链接无需数据库&#xff0c;输出即可转换…...

前端知识点(面试可看) —— JS

摘要 马上就要毕业啦&#xff0c;没有参加2023年的秋招&#xff0c;准备在最近开始找全职或者实习工作&#xff0c;然后也马上过年了&#xff0c;总结和理一下自己的知识要点&#xff0c;参加2024年的春招。 1. JS的执行流程 浏览器的V8引擎收到到执行的JS代码V8结构化这段代…...

CSRF总结

CSRF 文章目录 CSRF漏洞原理漏洞危害漏洞防护CSRF攻击流程CSRF和XSS的区别CSRF漏洞挖掘及利用 CSRF 跨站点请求伪造&#xff08;CSRF&#xff09;攻击者会诱导受害者点击事先伪造好的url或者链接&#xff0c;点击后&#xff0c;攻击者就可以盗用你的身份&#xff0c;以你的身份…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...