鸿蒙 ArkTs初识

news2024/11/20 1:39:09

前提:基于官网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.info
  console.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 aboutToAppear
      if (this.showChild) {
        Child()
      }
      // this.showChild为false,删除Child子组件,执行Child aboutToDisappear
      Button('delete Child').onClick(() => {
        this.showChild = false;
      })
      // push到Page2页面,执行onPageHide
      Button('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引用传递给ABuilder
      ABuilder({ 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.Green

  build() {
    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.coloradmin.cn/o/1417169.html

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

相关文章

Qt|大小端数据转换

后面打算写Qt关于网络编程的博客,网络编程就绕不开字节流数据传输,字节流数据的传输一般是根据协议来定义对应的报文该如何组包,那这就必然牵扯到了大端字节序和小端字节序的问题了。不清楚的大小端的可以看一下相关资料:大小端模…

【RTP】webrtc 学习3: webrtc对h264的rtp解包

rtp_rtcp\source\video_rtp_depacketizer_h264.cc【RTP】webrtc 学习2: webrtc对h264的rtp打包 中分析了打包过程的代码,这样再来看解析过程的源码就容易多了:本代码主要基于m79,m98类似。这里注明了jitterbuffer 会再次 做 解析stap-a 变为NAL units解析ParseFuaNalu 第一…

Jmeter 分布式测试

Jmeter单机进行压测,受到单台机器的性能影响,Jmeter支持分布式测试,用一个控制节点去控制多个工作节点去模拟更多的用户。 版本信息 内容版本号JDK1.8Jmeter5.6.2 分布式测试原理 jmeter 官网对分布式测试有说明,jmeter分布式…

RabbitMQ 死信交换机的详述➕应用

🥳🥳Welcome 的Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于RabbitMQ的相关操作吧 目录 🥳🥳Welcome 的Huihuis Code World ! !🥳🥳 一.什么是死信交换机 二. 死信队列…

说说你对vue的mixin的理解,有什么应用场景

mixin是什么 Vue中的mixin 局部混入全局混入注意事项: 使用场景源码分析Vue 的几种类型的合并策略 替换型合并型队列性叠加型小结 此文章,来源于印客学院的资料,这里只是分享,便于查漏补缺。 mixin是什么 Mixin 是 面向对象程序设计语言中…

一文理清楚-Docker 容器如何工作

Docker 容器如何工作 集装箱什么是虚拟机?虚拟化如何运作?什么是容器?什么是 Docker?总结 五星上将麦克阿瑟曾经说过:在docker面前,虚拟机就是个弟弟 集装箱 《盒子:集装箱如何让世界变得更小&…

车载电子电器架构 —— 多核处理器刷写策略

车载电子电器架构 —— 多核处理器刷写策略 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消…

内存管理(mmu)/内存分配原理/多级页表

1.为什么要做内存管理? 随着进程对内存需求的扩大,和同时调度的进程增加,内存是比较瓶颈的资源,如何更好的高效的利于存储资源是一个重要问题。 这个内存管理的需求也是慢慢发展而来,早期总线上的master是直接使用物…

C++:STL - string

C&#xff1a;STL - string basic_stringstringstring的常见构造string的输入输出operator<<c_stroperator>>getline string访问及遍历operator[ ] & atfont & back迭代器begin & endrbegin & rend 范围for string的容量操作size & lengthmax_…

用甘特图有效管理多个项目进度

当公司或组织同时承担多个项目时,合理规划各项目的时间节点与资源分配对确保高效完成至关重要。采用甘特图可以直观地展示多个项目的时间进程、关键里程碑以及资源分配情况,便于从宏观层面全面把控各项目的动态。 在线甘特图软件 zz-plan.com 提供了非常强大的时间轴规划功能,支…

CSS 多色正方形上升

<template><view class="loop cubes"><view class="item cubes"></view> <!-- 方块1 --><view class="item cubes"></view> <!-- 方块2 --><view class="item cubes"></vie…

C# 将HTML网页、HTML字符串转换为PDF

将HTML转换为PDF可实现格式保留、可靠打印、文档归档等多种用途&#xff0c;满足不同领域和情境下的需求。本文将通过以下两个示例&#xff0c;演示如何使用第三方库Spire.PDF for .NET和QT插件在C# 中将Html 网页&#xff08;URL&#xff09;或HTML字符串转为PDF文件。 HTML转…

【C语言】深入理解指针(3)数组名与函数传参

目录 &#xff08;一&#xff09;数组名的理解 &#xff08;1&#xff09;数组名是数组首元素的地址 &#xff08;2&#xff09;两个例外 &#xff08;二&#xff09;函数内数组传参 &#xff08;1&#xff09;一维数组传参 &#xff08;2&#xff09;二维数组传参 &…

以太网交换基础VLAN原理与配置

目录 7.以太网交换基础 7.1.以太网协议 7.2.以太网帧介绍 7.3.以太网交换机 7.4.同网段数据通信全过程 8.VLAN原理与配置 8.1.VLAN的基本概念 8.2.VLAN的应用 7.以太网交换基础 7.1.以太网协议 以太网是当今现有局域网(Local Area Network,LAN)采用的最通用的通信协议…

git使用指南——以gitlab为例

注册gitlab 自行注册 新建项目 选择新建一个空白的项目 上传项目 clone项目地址到本地 执行完之后&#xff0c;会在目录下生成如下内容&#xff1a;进入里面&#xff0c;选择.git&#xff0c;要上传的内容&#xff08;资料或代码复制到该目录下&#xff09;&#xff1a;…

界面组件DevExpress .NET MAUI中文教程 - 如何优化手机屏幕空间?

DevExpress拥有.NET开发需要的所有平台控件&#xff0c;包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具。 获取DevExpress v23.2正式版下载 Bottom Sheet是一个组件&#xff0c;它显示固定在屏幕底部的…

LeetCode:376.摆动序列

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;算法_仍有未知等待探索的博客-CSDN博客 题目链接&#xff1a;376. 摆动序列 - 力扣&#xff08;LeetCode&#xff09; 一、题目 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称…

【排序5】基数排序:数字的组织与整理艺术

&#x1f3a1;基数排序 &#x1f38a;1、基本思想&#x1f38a;2、基本步骤&#x1f38a;3、代码示例&#x1f38a;4、特性总结 &#x1f38a;1、基本思想 基数排序&#xff08;Radix Sort&#xff09;是一种非比较排序算法&#xff0c;它根据数字的每一位来对元素进行排序。它…

提示unzip :commad not found; 安装unzip教程

1.当使用unzip解压时 提示&#xff1a; unzip :commad not found; 2.安装命令 sudo yum install unzip 3.输入 y 确认 4.提示&#xff1a;完成 5.输入 unzip 文件名 解压-验证 6.完成

34.基于51单片机的智能停车位计时收费系统设计

一、系统功能介绍&#xff1a; 本设计基于 RFID智能识别和高速的视频图像和存储比较相结合&#xff0c;通过计算机的图像处理和自动识别&#xff0c;对车辆进出停车场的收费、车牌识别和车位诱导等&#xff0c;以实现停车场全方位智能管理。 本设计是以AT89C51 型单片机为主控芯…