鸿蒙 ArkTs初识

前提:基于官网3.1/4.0文档。参考官网文档
基于Android开发体系来进行比较和思考。(或有偏颇,自行斟酌)

吐槽:官网上的案例只有代码和文档解释,没有可以直接运行查看效果的模拟器,这一点上,Jetpack Compose是有的。

基本语法

1.结构

在这里插入图片描述
上面是官网上面的图,从结构来看,类似Jetpack Compose。 通过注解的方式来定义组件,这里给命名为了“装饰器”。
需要注意的是:@State表示组件中的状态变量,状态变量变化会触发UI刷新。类比livedata

2.引用的方式

// $r形式引入应用资源,可应用于多语言场景
Text($r('app.string.title_value'))
Image(this.imagePath)
Image('https://' + this.imageUrl)
Text(`count: ${this.count}`)// 这种方式在react中较为常见,应该是ts的写法

引用本地资源的方式是$r('app.string.title_value')。(感觉稍显复杂了)

3.this作用域

fn = () => {console.info(`counter: ${this.counter}`)this.counter++
}
Button('add counter').onClick(this.fn)

可以看到,this作用域是整个文件,而不是Android中的闭包作用域。

4.组件

@Component
struct MyComponent {build() {}
}

自定义组件标准范式如上。加上注解@Entry装饰的自定义组件将作为UI页面的入口。(这句话比较难理解,可以认为是export之类的用法,一个文件只有一个export,React项目中的特点。)

@Entry可以接受一个可选的LocalStorage的参数。——>这点类似于Android中的bundle,用来进行UI页面的数据传递。不确定该LocalStorage是否是livedata特点。

build
//不能在build里声明变量,需要放在build外。
build() {// 反例:不允许声明本地变量let a: number = 1;
}//不允许在UI描述里直接使用console.info,但允许在方法或者函数里使用——>可以理解为build{}是渲染作用域,不要添加打印
build() {// 反例:不允许console.infoconsole.info('print debug log');
}//不允许创建本地的作用域——>既然是渲染作用域,那就不必要再添加作用域,直接堆砌组件即可。(组件作用域里面可以调用方法)
build() {// 反例:不允许本地作用域{...}
}

不允许switch语法,如果需要使用条件判断,请使用if——>这一点甚是奇怪,都是判断语句还做不一样的差异对待

build() {Column() {// 反例:不允许使用switch语法switch (expression) {case 1:Text('...')break;case 2:Image('...')break;default:Text('...')break;}}
}
build() {Column() {// 反例:不允许使用表达式——>实际上这种写法在React中很常见,不确定知道jetpack compose是否如此设计(this.aVar > 10) ? Text('...') : Image('...')}
}
生命周期在这里插入图片描述

页面生命周期,即被@Entry装饰的组件生命周期,提供以下生命周期接口:
onPageShow:页面每次显示时触发一次,包括路由过程、应用进入前台等场景,仅@Entry装饰的自定义组件生效。
onPageHide:页面每次隐藏时触发一次,包括路由过程、应用进入后台等场景,仅@Entry装饰的自定义组件生效。
onBackPress:当用户点击返回按钮时触发,仅@Entry装饰的自定义组件生效。

组件生命周期,即一般用@Component装饰的自定义组件的生命周期,提供以下生命周期接口:
aboutToAppear:组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。
aboutToDisappear:在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。

生命周期相较于Android是做了减法。不确定是否有页面栈的设计模式,譬如说:栈顶复用之类,以及由此进行的bundle数据传递。

组件的销毁

组件的销毁是从组件树上直接摘下子树,所以先调用父组件的aboutToDisappear,再调用子组件的aboutToDisappear,然后执行初始化新页面的生命周期流程。

以下是官方示例:

// Index.ets
import router from '@ohos.router';@Entry
@Component
struct MyComponent {@State showChild: boolean = true;// 只有被@Entry装饰的组件才可以调用页面的生命周期onPageShow() {console.info('Index onPageShow');}// 只有被@Entry装饰的组件才可以调用页面的生命周期onPageHide() {console.info('Index onPageHide');}// 只有被@Entry装饰的组件才可以调用页面的生命周期onBackPress() {console.info('Index onBackPress');}// 组件生命周期aboutToAppear() {console.info('MyComponent aboutToAppear');}// 组件生命周期aboutToDisappear() {console.info('MyComponent aboutToDisappear');}build() {Column() {// this.showChild为true,创建Child子组件,执行Child aboutToAppearif (this.showChild) {Child()}// this.showChild为false,删除Child子组件,执行Child aboutToDisappearButton('delete Child').onClick(() => {this.showChild = false;})// push到Page2页面,执行onPageHideButton('push to next page').onClick(() => {router.pushUrl({ url: 'pages/Page2' });})}}
}@Component
struct Child {@State title: string = 'Hello World';// 组件生命周期aboutToDisappear() {console.info('[lifeCycle] Child aboutToDisappear')}// 组件生命周期aboutToAppear() {console.info('[lifeCycle] Child aboutToAppear')}build() {Text(this.title).fontSize(50).onClick(() => {this.title = 'Hello ArkUI';})}
}
@Builder作用

用来自定义构建函数,它就是个标识符。

ArkUI还提供了一种更轻量的UI元素复用机制@Builder,@Builder所装饰的函数遵循build()函数语法规则,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。

==所以这到底是个什么作用?==有没有这个的区别是什么,在build方法里面调用是指什么?有没有对比的案例?

待解答

//定义私有组件
@Builder MyBuilderFunction(){ ... }
//调用私有组件
this.MyBuilderFunction()//定义全局组件
@Builder function MyGlobalBuilderFunction(){ ... }
//调用全局组件
MyGlobalBuilderFunction()

可以看到,这里的function的作用,是将组件定义为全局的修饰符,而并不是函数的声明修饰符。这点容易让人误解

值传递和引用传递

引用传递

ArkUI提供$$作为按引用传递参数的范式 吐槽这个双美元符号作为范式,真的比较繁琐

ABuilder( $$ : { paramA1: string, paramB1 : string } );@Builder function ABuilder($$: { paramA1: string }) {Row() {Text(`UseStateVarByReference: ${$$.paramA1} `)}
}
@Entry
@Component
struct Parent {@State label: string = 'Hello';build() {Column() {// 在Parent组件中调用ABuilder的时候,将this.label引用传递给ABuilderABuilder({ paramA1: this.label })Button('Click me').onClick(() => {// 点击“Click me”后,UI从“Hello”刷新为“ArkUI”this.label = 'ArkUI';})}}
}

和TS使用方式是类似的,只不过这里的引用方式传值是带有状态的,即指向的引用值发生变化,也会引发@Builder方法内的UI刷新。

值传递

@Builder function ABuilder(paramA1: string) {//注意这个基本数据类型,是小写的string,与TS一致Row() {Text(`UseStateVarByValue: ${paramA1} `)}
}
@Entry
@Component
struct Parent {@State label: string = 'Hello';build() {Column() {ABuilder(this.label)}}
}

可以看到:很明显不是使用范式来进行参数的传递,而是场景的传参方式。这种值传递的方式和引用方式的传递的区别在于:前者值的变更不会触发@Builder组件的UI刷新。

@BuilderParam

作用是什么?

当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。为解决此问题,ArkUI引入了@BuilderParam装饰器,@BuilderParam用来装饰指向@Builder方法的变量,开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
由此看来,其实类似于Kotlin中的扩展函数。(注意扩展函数是扩展“函数”,不能扩展成员变量。暂不能确认这里是否可以扩展成员变量

如何用?

@BuilderParam装饰的方法只能被自定义构建函数(@Builder装饰的方法)初始化。

案例

@Component
struct Child {@BuilderParam aBuilder0: () => void;build() {Column() {this.aBuilder0()}}
}@Entry
@Component
struct Parent {@Builder componentBuilder() {Text(`Parent builder `)}build() {Column() {Child({ aBuilder0: this.componentBuilder })}}
}

官方举的案例硬是没看懂它的实际用途。——>实际上它类似于Android中addView(View)方法中的参数View,你可以丢进去LinearLayout、Button等等,它就是个抽象的占位参数。

@Styles

是什么*

样式装饰器

做什么用?

样式的集合,可以用来重用。类似于Android styles文件中定义的style。

怎么用?

// 定义在全局的@Styles封装的样式
@Styles function globalFancy  () {.width(150).height(100).backgroundColor(Color.Pink)
}@Entry
@Component
struct FancyUse {@State heightValue: number = 100// 定义在组件内的@Styles封装的样式@Styles fancy() {.width(200).height(this.heightValue).backgroundColor(Color.Yellow).onClick(() => {this.heightValue = 200})}build() {Column({ space: 10 }) {// 使用全局的@Styles封装的样式Text('FancyA').globalFancy ().fontSize(30)// 使用组件内的@Styles封装的样式Text('FancyB').fancy().fontSize(30)}}
}
  • @Styles仍旧是类似于@Builder一样,分为私有和全局定义(加上function修饰,就是全局)
  • @Styles里面包含了对点击事件的封装(也有可能有其他事件,譬如触摸事件),重点是它包含了“事件”,而不单单是通常意义上的样式
  • 引用方式直接就是通过链式的.操作
  • 不确定后续的style(包含组件本身的属性)是否会覆盖@Style的属性
@Extend

是什么?

@Styles用于样式的扩展,在@Styles的基础上,我们提供了@Extend,用于扩展原生组件样式——>也就是@Styles为自定义组件扩展样式,而这个@Extend是为原生组件扩展样式(譬如Text就是原生组件)
为什么要区分两种标识符?

什么作用?

作用是和@Styles一样的,不过它可以传参,@Styles的函数时不可以传参的。这意味着它更灵活。但是它只能在组件内部定义,而不能全局定义,也就是不能使用function。当然,并没有解释为什么不可以,估计与设计逻辑冲突有关

怎么用?

@Entry
@Component
struct FancyUse {@State label: string = 'Hello World'build() {Row({ space: 10 }) {Text(`${this.label}`).fontStyle(FontStyle.Italic).fontWeight(100).backgroundColor(Color.Blue)Text(`${this.label}`).fontStyle(FontStyle.Italic).fontWeight(200).backgroundColor(Color.Pink)Text(`${this.label}`).fontStyle(FontStyle.Italic).fontWeight(300).backgroundColor(Color.Orange)}.margin('20%')}
}

上面是一种通用写法,一种样式写了三次,那么优化之后如下:

@Extend(Text) function fancyText(weightValue: number, color: Color) {.fontStyle(FontStyle.Italic).fontWeight(weightValue).backgroundColor(color)
}@Entry
@Component
struct FancyUse {@State label: string = 'Hello World'build() {Row({ space: 10 }) {Text(`${this.label}`).fancyText(100, Color.Blue)Text(`${this.label}`).fancyText(200, Color.Pink)Text(`${this.label}`).fancyText(300, Color.Orange)}.margin('20%')}
}

很明显,封装性更好,可读性更强了。

stateStyles

是什么
状态样式,这样不好理解。关于组件状态的回调——>这里理解可能比较清晰。(具体见下面的案例)

怎么用

@Entry
@Component
struct CompWithInlineStateStyles {@State focusedColor: Color = Color.Red;normalColor: Color = Color.Greenbuild() {Column() {Button('clickMe').height(100).width(100).stateStyles({normal: {.backgroundColor(this.normalColor)},focused: {.backgroundColor(this.focusedColor)}}).onClick(() => {this.focusedColor = Color.Pink}).margin('30%')}}
}

focused:获焦态。
normal:正常态。
pressed:按压态。
disabled:不可用态。

因此,它至少上面四种状态可供回调设置样式。——>不确定是否可以在这个状态回调方法进行其他逻辑处理。(可能不可以?因为是使用的.方法的方式

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

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

相关文章

【C++修行之道】STL(初识list、stack)

目录 一、list 1.1list的定义和结构 以下是一个示例,展示如何使用list容器: 1.2list的常用函数 1.3list代码示例 二、stack 2.1stack的定义和结构 stack的常用定义 2.2常用函数 2.3stack代码示例 一、list 1.1list的定义和结构 list的使用频率不高&#…

SQL注入:二次注入

SQL注入系列文章: 初识SQL注入-CSDN博客 SQL注入:联合查询的三个绕过技巧-CSDN博客 SQL注入:报错注入-CSDN博客 SQL注入:盲注-CSDN博客 目录 什么是二次注入? 二次注入演示 1、可以注册新用户 2、可以登录->…

1Panel CloudFlare证书申请失败的解决方案

在升级1Panel后,使用 CloudFlare DNS验证时,会提示 [*.biliwind.com] [*.biliwind.com] acme: error presenting token: cloudflare: failed to find zone biliwind.com.: ListZonesContext command failed: Invalid request headers (6003) 为解决此问…

2023年全球软件开发大会(QCon广州站2023):核心内容与学习收获(附大会核心PPT下载)

在全球化的科技浪潮中,软件开发行业日新月异,持续推动着社会经济的飞速发展。本次峰会以“引领未来,探索无限可能”为主题,聚焦软件开发领域的最新技术、最佳实践和创新思想。来自世界各地的顶级专家、企业领袖和开发者齐聚一堂&a…

防范[myers@airmail.cc].mkp攻击:解密[myers@airmail.cc].mkp勒索病毒的方法

引言: 随着科技的迅猛发展,网络安全问题日益突出,而勒索病毒也成为当前互联网威胁中的一大焦点。其中,[datastorecyberfear.com].mkp [hendersoncock.li].mkp [hudsonLcock.li].mkp[myersairmail.cc].mkp勒索病毒以其强大的加密能…

什么是防抖和节流?有什么区别?如何实现?

文章目录 一、是什么定义代码实现节流防抖 二、区别三、应用场景 一、是什么 本质上是优化高频率执行代码的一种手段 如:浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源…

与供应商无关的 SOAR 在克服孤立的安全挑战中的作用

孤立安全是指不同的安全工具和流程独立运行,它们之间没有有效的通信或数据共享的情况。这种分散的方法在许多组织中很常见,通常是由于随着时间的推移逐渐采用安全解决方案,每个解决方案都根据其特定功能进行选择,而不考虑整体集成…

【hcie-cloud】【23】容器编排【k8s】【Kubernetes常用工作负载、Kubernetes调度器简介、Helm简介、缩略词】【下】

文章目录 单机容器面临的问题、Kubernetes介绍与安装、Kubernetes对象的基本操作、Kubernetes YAML文件编写基础Kubernetes常用工作负载Kubernetes常用工作负载简介创建一个无状态nginx集群无状态工作负载Deployment说明无状态工作负载Deployment常见操作创建一个有状态的MySQL…

04 Redis之命令(Hash型Value命令+List型Value命令+Set型Value命令+有序集合ZSET型Value命令)

3.4 Hash型Value命令 Hash 表就是一个映射表 Map,也是由键-值对构成,为了与整体的 key 进行区分,这里的键称为 field,值称为 value。注意,Redis 的 Hash 表中的 field-value 对均为 String 类型。 3.4.1 hset  格…

第一个hello驱动

Linux驱动程序的分类 字符设备驱动、块设备驱动和网络设备驱动。 Linux驱动程序运行方式 把驱动程序编译进内核里面,这样内核启动后就会自动运行驱动程序了;把驱动程序编译成以.ko为后缀的模块文件,然后在Linux启动后,我们自己…

微信小程序(二十一)css变量-定义页面主题色

注释很详细,直接上代码 上一篇 新增内容: 1.使用css变量 2.消除按钮白块影响 3.修改图标样式 源码: npmTest.json {"navigationStyle": "custom","usingComponents": {//引入vant组件"van-nav-bar"…

Linux多线程——线程池

本章Gitee仓库:线程池、单例模式 文章目录 1. 池化技术简述2. 线程池3. 单例模式3.1 单例模式特点3.2 饿汉方式和懒汉方式3.3 单例模式线程安全 1. 池化技术简述 C中的STL,当空间不够时,会自动扩容,这个并不是我们需要多少&#…

sqli-labs闯关

目录 1.安装靶场2.了解几个sql常用知识2.1联合查询union用法2.2MySQL中的通配符:2.3常用函数2.4数据分组 3.mysql中重要的数据库和表4.开始闯关4.1 Less-14.1.1 首先进行一次常规的注入4.1.2 深入解析 1.安装靶场 1.首先推荐使用github下载靶场源码 https://githu…

Matlab处理excel数据

我们新建个excel文档,用Matlab读取里面的内容,计算和判断里面的计算结果是否正确,并打印到另一个文档当中。 新建文档 新建输入文档,文件名TestExcel 编写脚本 [num,txt] xlsread(TestExcel.xlsx); SNcode num(:,1);%从序号中…

《微信小程序开发从入门到实战》学习九十六

7.2 基础内容组件 7.2.4 progress组件 progress组件的示例代码如下&#xff1a; <progress percent"20" show-info /> 7.3 表单组件 表单组件是用于收集信息的组件。第三章介绍了许多表单组件&#xff0c;包括form、input、textarea、picker、switch、butt…

eclipse启动Java服务及注意事项

1、导入项目 选择file——》import…——》Generate——》Exiting Projects into Workspace——》选择要导入的项目 2、添加tomcat 1&#xff09;点击Serves——》No servers are available. Click this link to create a new server… 2&#xff09;点击“Add…” 3&…

YOLO 全面回顾:从最初的YOLOv1到最新的YOLOv8、YOLO-NAS,以及整合了 Transformers 的 YOLO

YOLO 全面回顾 综述评估指标YOLO v1YOLO v2YOLO v3YOLO v4YOLOv5 与 Scaled-YOLOv4 YOLORYOLOXYOLOv6YOLOv7DAMO-YOLOYOLOv8PP-YOLO, PP-YOLOv2, and PP-YOLOEYOLO-NASYOLO with Transformers 综述 论文&#xff1a;https://arxiv.org/pdf/2304.00501.pdf 代码&#xff1a;gi…

MySQL知识点总结(一)——一条SQL的执行过程、索引底层数据结构、一级索引和二级索引、索引失效、索引覆盖、索引下推

MySQL知识点总结&#xff08;一&#xff09;——一条SQL的执行过程、索引底层数据结构、一级索引和二级索引、索引失效、索引覆盖、索引下推 一条SQL的执行过程索引底层数据结构为什么不使用二叉树&#xff1f;为什么不使用红黑树?为什么不使用hash表&#xff1f;为什么不使用…

Windows Qt C++ VTK 绘制三维曲线

Qt 自带数据可视化从文档上看&#xff0c;只能实现三维曲面。 QwtPlot3D在Qt6.6.0上没编译通过。 QCustomPlot 只能搞二维。 VTK~搞起。抄官网demo。 后续需求&#xff1a; 1、对数轴 2、Y轴逆序 3、Z轴值给色带&#xff0c;类似等高线图的色带 期待各位大佬多多指导。…

ad18学习笔记十六:v割

所谓“V割”是印刷电路板&#xff08;PCB&#xff09;厂商依据客户的图纸要求&#xff0c;事先在PCB的特定位置用转盘刀具切割好的一条条分割线&#xff0c;其目的是为了方便后续SMT电路板组装完成后的分板之用&#xff0c;因为其切割后的外型看起来就像个英文的“V”字型&…