一、组件基础
1.开发环境
1. 简介
HarmonyOS是新一代的智能终端操作系统,为不同设备的智能化、互联与协同提供了统一的语言。带来简洁,流畅,连续,安全可靠的全场景交互体验。
2.DevEco Studio
-
下载DevEco Studio,选择对应系统
-
双击运行.exe文件进行安装,一直点next即可
-
双击运行软件
-
到这里可以选择安装NodeJs和ohpm包管理器
-
选择安装sdk,安装完成即可
3.HelloWorld
创建一个空项目:
4.效果预览
效果预览方法
- Previewer 预览模式
- Local Emulator 本地模拟器
- Remote Emulator 远程模拟器
- Remote Device 远程真机
- Local Device 本地真机
推荐使用 Previewer 预览 和 Local Emulator 本地模拟器;
尤其推荐使用 遥遥领先 真机调试;
- Previewer 预览
场景:静态页面(没有组件间数据通信、不涉及到网络请求)
条件:有 @Entry 或 @Preview 装饰器页面
- Local Emulator 本地模拟器
场景:动态页面(几乎全场景,一些无法模拟的硬件功能)
-
其他方式
- Remote Emulator 远程模拟器
- Remote Device 远程真机
- Local Device 本地真机
5.工程结构
Stage 模型
了解App结构关系,等后面我们项目阶段来讲一些工程配置文件作用,现在你要知道:
entry 是一个 Module 应用包
entryability 是一个 UIAbility 包含用户界面的应用组件
pages 是页面
components 可以是组件
2.组件基础
1.什么是ArkTS
ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,继承了TS的所有特性,是TS的超集。
扩展能力如下:
-
基本语法
定义声明式UI、自定义组件、动态扩展UI元素;
提供ArkUI系统组件,提供组件事件、方法、属性;
共同构成 UI 开发主体 -
状态管理
组件状态、组件数据共享、应用数据共享、设备共享;
-
渲染控制
条件渲染、循环渲染、数据懒加载;
声明式UI? 问题?
通过一段 HTML 标签展示出对应的页面方便,还是使用document.createElement(‘tag’)创建标签构建页面方便?显然是 HTML , 其实 HTML 本身就是声明式的,通过描述的方式去声明 UI 界面。 一些前端框架也是声明式UI,如 Vue 使用的 tempalte 模板,如 React 使用的 JSX。 在例如现在的 Jetpack Compose SwiftUI Flutter 等APP开发技术也是声明式。
2.组件结构
ArkTS通过装饰器 @Component 和 @Entry 装饰 struct 关键字声明的数据结构,构成一个自定义组件。
自定义组件中提供了一个 build 函数,开发者需在该函数内以链式调用的方式进行基本的 UI 描述,UI 描述的方法请参考 UI 描述规范。
- 页面组件
@Entry
@Component
struct Index {
// 工程默认显示 `Index` 页面组件
// build 是声明UI的位置
build() {
Text('页面组件')
}
}
- 自定义组件
@Component
export struct Test {
build() {
Text('自定义组件')
}
}
import {
Test } from '../component/Test'
@Entry
@Component
struct Index {
build() {
Row(){
Text('页面组件')
Test()
}
}
}
为了更好维护,自定义组件通常会新建一个文件 xxx.ets,通过模块化语法导出导入(默认|按需)使用。
注意
- @Entry @Component 是页面组件,将来需要页面跳转就需要再定义一个页面。
- @Component自定义组件,一个页面组件下可以有多个自定义组件。
- build(){} 只能有一个根元素
3.系统组件(ArkUI)
常用系统组件 Text Column Row Button TextInput 更多组件
- Text 文本组件
- Column 列组件,纵向排列,Flex布局主轴是Y
- Row 行组件,横向向排列,Flex布局主轴是X
- Button 按钮组件
- InputText 输入框组件
实现一个简易登录界面:
@Entry
@Component
struct Index {
build() {
Column(){
Row(){
Text('手机号')
TextInput()
}
Row(){
Text('验证码')
TextInput()
}
Row(){
Button('重置')
.backgroundColor('#c3c4c5')
Button('登录')
}
}
}
}
注意
ArkUI 组件一般都是 Flex 模式,大部分布局可以由行和列组成。
4.组件状态
- 组件变量,不具备驱动UI更新能力
@Entry
@Component
struct Index {
count = 100
build() {
Text(this.count.toString())
.onClick(() => this.count++)
}
}
- 状态变量,指驱动UI更新的数据,加上 @State 装饰器即可,注意:加上类型和初始值
import promptAction from '@ohos.promptAction'
@Entry
@Component
struct Index {
//State注解定义变量,变量具有响应式功能
@State
//类型不可为any、undefined、null、与复杂类型的联合类型
count:number=100
build() {
Column(){
Text(this.count.toString())
Button('+1').onClick(()=>{
this.count++
console.log(this.count.toString())
//promptAction是提示组件,方便查看结果
promptAction.showToast({
message:this.count.toString()})
})
}
}
}
注意
加上类型和初始值
状态变量不可设置的类型有:any undefined null 与复杂类型的联合类型
绑定事件在系统组件后链式使用 onXxxxx 进行绑定即可 使用 @ohos.promptAction 可以进行轻提示
promptAction.showToast({ message: ‘Tip’ })
练习案例→实现登录表单数据收集、重置、模拟提交
import promptAction from '@ohos.promptAction'
@Entry
@Component
struct Index {
@State
phone: string = ''
@State
code: string = ''
build() {
Column() {
Row() {
Text('手机号')
TextInput({
text: this.phone })
.onChange((value) => this.phone = value)
}
Row() {
Text('验证码')
TextInput({
text: this.code })
.onChange((value) => this.code = value)
}
Row() {
Button('重置')
.backgroundColor('#c3c4c5')
.onClick(() => {
this.code = ''
this.phone = ''
})
Button('登录')
.onClick(() => {
if (this.phone && this.code) {
promptAction.showToast({
message: `${
this.phone}登录成功` })
}else {
promptAction.showToast({
message: `请输入手机号或验证码` })
}
})
}
}
}
}
3.样式处理
1.语法(枚举&链式)
ArkTS以声明方式组合和扩展组件来描述应用程序的UI;
同时还提供了基本的属性、事件和子组件配置方法,帮助开发者实现应用交互逻辑。
-
样式属性
属性方法以 . 链式调用的方式配置系统组件的样式和其他属性,建议每个属性方法单独写一行
@Entry @Component struct Index { build() { Column() { Text('文本') .backgroundColor(Color.Pink) .fontSize('60') .width('100%') .height(100) .fontColor(Color.Orange) .textAlign(TextAlign.Center) } .height('100%') .backgroundColor(Color.Blue) .justifyContent(FlexAlign.Center) } }
-
枚举值
如Color.Pink、TextAlign.Center都是通过枚举值设置样式
2.单位vp和适配
-
vp 是什么?virtual pixel
屏幕密度相关像素,根据屏幕像素密度转换为屏幕物理像素,当数值不带单位时,默认单位 vp;在实际宽度为1440物理像素的屏幕上,1vp 约等于 3px(物理像素)
上图的意思是,使用这个单位在不同屏幕物理分辨率的实际尺寸一致(A设备1英寸,B设备1英寸)。
-
之前 vw 、rem 和 rpx 相对于屏幕宽度的单位,可以实现等比例适配,vp 可以吗?
import promptAction from '@ohos.promptAction' @Entry @Component struct Index { build() { Text('演示') .width('100%') .backgroundColor('red') .onAreaChange((oldArea, newArea) => { promptAction.showToast({ // 1. onAreaChange改变尺寸后会触发 // 2. newArea为现在元素尺寸 message: newArea.width.toString() }) }) } }
-
根据官方的文档,结合自己的理解,采用:伸缩布局,网格系统,栅格系统进行布局适配
伸缩 layoutWeight(flex: number) 占剩余空间多少份,可以理解成CSS的 flex: 1
@Entry @Component struct Index { build() { Row(){ Text('left') .layoutWeight(1) .backgroundColor('red') Text('right') .layoutWeight(2) .backgroundColor('green') } .width('100%') } }
等比例,设置元素宽高比 aspectRatio(ratio: number)
@Entry @Component struct Index { build() { Text('left') .width('50%') // 宽高比例 .aspectRatio(1) .backgroundColor('red') } }
注意
- vp 是鸿蒙默认单位,和屏幕像素有关,最终表现视觉大小在任何设备一致
- 鸿蒙一般以伸缩layoutWeight、网格、栅格进行布局适配,如要等比例缩放可以设置高宽比 aspectRatio
3.练习案例–>评论
@Entry
@Component
struct Index {
build() {
Column() {
Row() {
Row() {
//Image,$r为固定函数,取resource下资源,app为固定路径
Image($r('app.media.ic_public_arrow_left'))
.width(16)
.aspectRatio(1)
}
.width(24)
.aspectRatio(1)
.backgroundColor('#f5f5f5')
.borderRadius(12)
//水平对齐
.justifyContent(FlexAlign.Center)
.margin({
left: 16 })
Text('评论回复')
//沾满剩下的屏幕
.layoutWeight(1)
.textAlign(TextAlign.Center)
.padding({
right: 40 })
}
.height(40)
.border({
width: {
bottom: 0.5 }, color: '#e4e4e4' })
Row() {
Image($r("app.media.panda"))
.width(62)
.aspectRatio(1)
.borderRadius(16)
Column({
space: 5 }) {
Text('张三')
.width('100%')
.fontWeight(FontWeight.Bold)
Text('大理石能雕刻出肌肉与皮肤的质感,那个年代的工匠好牛啊')
.width('100%')
Row() {
Text('10-21 IP属地北京')
.fontSize(12)
.fontColor('#c3c4c5')
Row() {
Image($r('app.media.fav'))
.width(12)
//svg图标可以填充颜色
.fillColor('#c3c4c5')
Text('100')
.fontSize(12)
.fontColor('#c3c4c5')
}
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
}
.padding({
left: 10