鸿蒙系列--装饰器
一、基础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 })}}
}
描述:
- CountModifier自定义组件的Button.onClick点击事件自增count
- 由于@State count变量更改,子组件TotalView中的@Prop被更新,其@Watch('onCountUpdated')方法被调用,更新了子组件TotalView 中的total变量
- 子组件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 })}}
}
描述:
- BasketModifierPage组件的Button.onClick向BasketModifier shopBasket中添加条目
- @Link装饰的BasketViewer shopBasket值发生变化
- 状态管理框架调用@Watch函数BasketViewer onBasketUpdated 更新BasketViewer TotalPurchase的值
- @Link shopBasket的改变,新增了数组项,ForEach组件会执行item Builder,渲染构建新的Item项;@State totalPurchase改变,对应的Text组件也重新渲染
- 重新渲染是异步发生的
相关文章:

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

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

Redis(二)数据类型
文章目录 官网备注十大数据类型StringListHashSetZSetBitmapHyperLogLog:GEOStreamBitfield 官网 英文:https://redis.io/commands/ 中文:http://www.redis.cn/commands.html 备注 命令不区分大小写,key区分大小写帮助命令help…...
2023年广东省网络安全B模块(笔记详解)
模块B 网络安全事件响应、数字取证调查和应用安全 一、项目和任务描述: 假定你是某网络安全技术支持团队成员,某企业的服务器系统被黑客攻击,你的团队前来帮助企业进行调查并追踪本次网络攻击的源头,分析黑客的攻击方式,发现系统漏洞,提交网络安全事件响应报告,修复系统…...

每日力扣算法题(简单篇)
543.二叉树的直径 原题: 给你一棵二叉树的根节点,返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 解题思路: …...

Flume基础知识(三):Flume 实战监控端口数据官方案例
1. 监控端口数据官方案例 1)案例需求: 使用 Flume 监听一个端口,收集该端口数据,并打印到控制台。 2)需求分析: 3)实现步骤: (1)安装 netcat 工具 sudo yum …...

通过IP地址如何进行网络安全防护
IP地址在网络安全防护中起着至关重要的作用,可以用于监控、过滤和控制网络流量,识别潜在威胁并加强网络安全。以下是通过IP地址进行网络安全防护的一些建议: 1. 建立IP地址白名单和黑名单: 白名单:确保只有授权的IP地…...
Vue.js 中使用 Watch 选项实现动态问题判断与展示答案
组件结构 以下是组件的基本结构: <template><div><!-- 输入框,用于输入问题 --><p>提出一个是/否问题:<input v-model"question" :disabled"loading" /></p><!-- 显示答案 --&…...
python笔记-自用
2024/1/3# python用号实现字符串的拼接,非字符串不能拼接 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字符串占…...

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

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 实现批处理任务,保姆级教程 步骤 1.建表 建表sql CREATE TABLE student (id int NOT NULL AUTO_INCREMENT,name varchar(100) NOT NULL C…...
答案解析——C语言—第2次作业:转义字符
本次作业的链接如下:C语言—第2次作业:转义字符 1.下面哪个不是C语言内置的数据类型: C char //字符数据类型short //短整型int //整形long //长整型long long //更长的整形float //单精度浮点数double //双精度浮点数 …...

HTML5-新增表单input属性
新增表单属性 form控件主要新增的属性: autocomplete 是否启用表单的自动完成功能,取值:on(默认)、off novalidate 提交表单时不进行校验,默认会进行表单校验 autocomplete属性 概念:autocomplete属性…...

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

nifi详细介绍--一款开箱即用、功能强大可靠,可用于处理和分发数据的大数据组件
目录 目录 一、引言 二、NiFi 的历史背景介绍 三、NiFi 是什么? 核心特性 应用领域 四、NIFI 入门 五 、NiFi 工作流程 六、实际应用场景 七、优势总结 一、引言 NiFi(Apache NiFi),全名为“Niagara Files”࿰…...
K8S Dashboard登录Token过期问题处理
整体思路 用户访问一个页面,在该页面中设置一个超链接,点击跳转至K8S Dashboard;跳转后,使用剪贴板上已复制的Token粘贴到Dashboard页面中的输入框登录即可。 写个定时任务将Token复制到页面上,过期了重新再登…...

x-cmd pkg | trafilatura - 网络爬虫和搜索引擎优化工具
目录 简介首次用户技术特点竞品和相关作品进一步阅读 简介 trafilatura 是一个用于从网页上提取文本的命令行工具和 python 包: 提供网络爬虫、下载、抓取以及提取主要文本、元数据和评论等功能可帮助网站导航和从站点地图和提要中提取链接无需数据库,输出即可转换…...
前端知识点(面试可看) —— JS
摘要 马上就要毕业啦,没有参加2023年的秋招,准备在最近开始找全职或者实习工作,然后也马上过年了,总结和理一下自己的知识要点,参加2024年的春招。 1. JS的执行流程 浏览器的V8引擎收到到执行的JS代码V8结构化这段代…...

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

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...