CPU都被干冒烟了,拥抱HarmonyOS第二天,自定义组件(上)

简介: CPU都被干冒烟了,拥抱HarmonyOS第二天,自定义组件

在这两天的学习过程中,我发现了一个巨诡异的事情,那就是明明第一次在文档中找到的内容,结果第二次想要通过搜索找到他,打死都找不到,这种情况出现了三次。arkUI 的文档是真神奇!


那种诡异感甚至差点让我以为自己穿越了...


第二天没有什么实际的产出,但是学习进展非常明显,直接把自定义组件相关的知识 ~


学!完!了!


我把主要学习精力放在了区别 arkUI 和 React/vue 的差异、以及在封装一些比较有难度的基础组件的实现方式上。


比如我想要封装一个体验良好的表单组件,那么我的学习思路是


  • T、学习思路
  • 1、复杂UI布局应该怎么做 ✅
  • 2、基础的动画细节应该如何实现 ✅
  • 3、数据管理应该怎么做 ✅
  • 4、表单验证应该怎么做 ✅
  • 5、数据量复杂的时候有没有可能存在性能问题,还没有验证过,若在实践中遇到问题,针对性的优化即可


如果目的一样,当我攻克了和 React 的差异,在 HarmonyOS 上基于 arkUI 实现一套大厂可商用的基础组件就比较简单了。


这意味着什么呢?


意味着我已经可以开始撸大型实战项目啦!剩下还有很多不熟悉的组件和系统能力,只需要在用到的时候,阅读文档拿来使用,在后续的开发过程中慢慢熟练即可。所以呢,有想要组建 HarmonyOS 开发团队的老板们可以开始联系我了,我给你们当技术指导,哈哈。


我今天学习的主要内容包括:


系统组件生命周期
onAppear:组件挂载到组件树之后调用
onDisAppear:组件卸载时调用
页面组件生命周期
onPageShow:页面每次显示时触发
onPageHide:页面每次隐藏时触发
onBackPress:用户点击返回按钮时触发
自定义组件生命周期
aboutToAppear:组件即将出现时触发,在 build 之前
aboutToDisappear:组件即将销毁时触发
组件级别状态管理
@State
@Prop
@Link
@Provide/@Consume
@Observed
@ObjectLink
应用级别状态管理
@StorageProp
@StorageLink
@LocalStorageProp
@LocalStorageLink
其他状态管理
@Watch
$$ 运算符
T. 状态交互
1. 传参与接受参数
2. 子组件控制父组件
3. 父组件控制子组件

练习了大量的交互 Demo,并成功封装了两个可商用的基础组件

Icon Lottie
字体图标组件 Lottie 动画组件

在 React 里,一个 state 一个 props 就完事了,万万没想到在 arkUI 里知识点这么多。在研究组件交互的过程中,我的 CPU 直接被干冒烟了,根据我的学习感受,这必定会成为一个比较难掌握的点,要吃透他不太容易


01组件分类


在 arkUI 里,组件主要分为三个大类


  • 系统组件 主要是指系统原生提供的一系列组件,例如 Text、Button、CheckBox 等
  • 页面组件 被装饰器 @Entry 装饰的组件为页面组件,他表示一个页面的入口,该组件为页面的根节点
  • 自定义组件 我们可以通过装饰器 @Component 定义新的组件


02组件基础语法


一个页面组件中最基础的写法如下

@Entry
@Component
struct MyComponent {
  build() {
    Text('hello world!')
  }
}

页面组件必须被 @Entry 装饰。build 方法中包含所有的页面元素。在上面这个例子中,Text 组件执行实际上是一个初始化的过程,但是由于关键字 struct 的作用,因此省略了 new.


系统提供的基础组件以 . 链式调用的方式设置当前组件的样式


例如,设置 Text 组件的字体大小

Text('test')
  .fontSize(12)

也可以同时配置多个属性

Image('test.jpg')
  .alt('error.jpg')    
  .width(100)    
  .height(100)

除了直接传递常量参数之外,还可以传递变量和表达式

Text('hello')
  .fontSize(this.size)
Image('test.jpg')
  .width(this.count % 2 === 0 ? 100 : 200)    
  .height(this.offset + 100)

arkUI 系统提供了一些全局的枚举类型,可以作为参数传递

Text('hello')
  .fontSize(20)
  .fontColor(Color.Red)
  .fontWeight(FontWeight.Bold)

如果某个元素想要设置事件监听,同样以 . 链式调用的方式使用

Button('Click me')
  .onClick(() => {
    this.myText = 'ArkUI';
  })


this


习惯了箭头函数和函数式组件的 React 开发者就要注意了,在面向对象的语境下,需要随时确保 this 的引用发生变化,因此如下两种情况都需要使用 bind 绑定 this

Button('add counter')
  .onClick(function(){
    this.counter += 2;
  }.bind(this))

这是个坑啊,折磨了多少开发者,他又来了!

myClickHandler(): void {
  this.counter += 2;
}
...
Button('add counter')
  .onClick(this.myClickHandler.bind(this))


组件嵌套


组件嵌套的方式,就是在父组件后面添加 {},所有的容器组件都支持嵌套子组件

Column() {
  Text('Hello')
    .fontSize(100)
  Divider()
  Text(this.myText)
    .fontSize(100)
    .fontColor(Color.Red)
}


@Builder


有的时候我们希望把一段组件的逻辑单独抽离出来,可以使用 @Builder 装饰器来声明一个自定义构建函数

@Entry
@Component
struct MyComponent {
  @Builder helloHarmonyOS() {
    Text('Hello HarmonyOS')
  }
  build() {
    Row() {
      Text('hello world!')
      this.helloHarmonyOS()
    }
  }
}

但是这个 @Builder 装饰器在传参数的时候,有特别的规则,我们后面在学习状态管理的时候一起分享

我们可以在一个组件里定义多个 @Builder 声明的函数,也可以在全局定义

@Builder 
function MyGlobalBuilderFunction() {
}


@Styles


我们可以使用 @Styles 装饰器来解决样式复用的问题。

@Entry
@Component
struct MyComponent {
  @Builder helloHarmonyOS() {
    Text('Hello HarmonyOS')
      .fancy()
  }
  @Styles fancy() {
    .width('100%')
    .height(40)
    .backgroundColor(Color.Pink)
  }
  build() {
    Row() {
      Text('hello world!')
        .fancy()
      this.helloHarmonyOS()
    }
  }
}

需要注意的是,@Styles 目前仅支持通用属性和通用事件。


具体属性有哪些可以去官方文档查看,或者根据 DevEco 的代码提示来编写


@Styles 也不支持传入参数

// bad
@Styles 
- function globalFancy (value: number) {
-  .width(value)
}

@Styles 可以定义在组件内,也可以定义在全局,在全局定义时需要在方法名之前添加 function 关键字

// 全局
@Styles function functionName() { ... }
// 在组件内
@Component
struct FancyUse {
  @Styles fancy() {
    .height(100)
  }
}

组件内 @Styles 的优先级高于全局 @Styles。 框架优先找当前组件内的 @Styles,如果找不到,则会全局查找。

// 定义在全局的@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 还不支持跨文件引入,这里的全局只能是同一个文件的全局 ~


@Extend


我们可以使用 @Extend 扩展原生组件样式

@Extend(UIComponentName) 
function functionName {
  ...
}
  • @Extend 仅支持全局定义
  • @Extend 支持封装指定原生组件的私有属性和方法,以及相同指定组件的 @Extend 方法
// 支持Text的私有属性fontColor
@Extend(Text) function fancy () {
  .fontColor(Color.Red)
}
// superFancyText可以调用预定义的fancy
@Extend(Text) 
function superFancyText(size:number) {
  .fontSize(size)
  .fancy()
}
  • @Extend 支持参数传入
// xxx.ets
@Extend(Text) 
function fancy (fontSize: number) {
  .fontColor(Color.Red)
  .fontSize(fontSize)
}
@Entry
@Component
struct FancyUse {
  build() {
    Row({ space: 10 }) {
      Text('Fancy')
        .fancy(16)
      Text('Fancy')
        .fancy(24)
    }
  }
}

传入的参数可以是 function

@Extend(Text) 
function makeMeClick(onClick: () => void) {
  .backgroundColor(Color.Blue)
  .onClick(onClick)
}
@Entry
@Component
struct FancyUse {
  @State label: string = 'Hello World';
  onClickHandler() {
    this.label = 'Hello ArkUI';
  }
  build() {
    Row({ space: 10 }) {
      Text(`${this.label}`)
        .makeMeClick(this.onClickHandler.bind(this))
    }
  }
}
相关文章
|
11天前
|
JSON 前端开发 网络架构
鸿蒙开发:一文探究Navigation路由组件
如果你还在使用router做为页面跳转,建议切换Navigation组件作为应用路由框架,不为别的,因为官方目前针对router已不在推荐。
149 101
鸿蒙开发:一文探究Navigation路由组件
|
19天前
「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息,页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。
127 38
|
11天前
|
人工智能 前端开发 API
鸿蒙开发:简单自定义一个绘制画板
画板,最重要的就是绘制,保证线条绘制的连续性,这一点很重要,还有就是beginPath方法一定要调用,否则更改颜色以及绘制就会出现不连续以及颜色设置错误问题。
58 14
|
8天前
|
索引 API
鸿蒙开发:自定义一个股票代码选择键盘
金融类的软件,特别是股票基金类的应用,在查找股票的时候,都会有一个区别于正常键盘的键盘,也就是股票代码键盘,和普通键盘的区别就是,除了常见的数字之外,也有一些常见的股票代码前缀按钮,方便在查找股票的时候,更加方便的进行检索。
鸿蒙开发:自定义一个股票代码选择键盘
|
8天前
|
API
鸿蒙开发:自定义一个英文键盘
实现方式呢,有很多种,目前采用了比较简单的一种,如果大家采用网格Grid组件实现方式,也是可以的,但是需要考虑每行的边距以及数据,还有最后两行的格子占位问题。
鸿蒙开发:自定义一个英文键盘
|
8天前
|
API
鸿蒙开发:自定义一个车牌字母键盘
车牌字母键盘和一般的键盘还有很大区别的,大家可以发现,键盘上是少一个字母的,因为I字母具有混淆性,所以这个字母是不在车牌键盘内的。
鸿蒙开发:自定义一个车牌字母键盘
|
9天前
鸿蒙开发:组件样式的复用
如果要实现多页面之间的组件属性样式复用,建议使用AttributeModifier,如果是单页面,通用属性可以使用@Styles,组件自有属性可以使用@Extend。
鸿蒙开发:组件样式的复用
|
16天前
|
JavaScript Java 容器
鸿蒙应用开发从入门到入行 - 篇4:层叠布局、自定义组件、ForEach
导读:在本篇文章里,您将掌握层叠布局、自定义组件的用法,特别是自定义组件将来的开发中必然会用,其中应该特别关注自定义组件的一些规范与装饰器。
53 7
鸿蒙应用开发从入门到入行 - 篇4:层叠布局、自定义组件、ForEach
|
15天前
鸿蒙开发:一个轻盈的上拉下拉刷新组件
在和可滑动组件使用的时候,记得一定要和nestedScroll属性配合使用,用于解决滑动冲突,除此之外,还需要传递滑动组件的scroller属性,用于手势操作。
鸿蒙开发:一个轻盈的上拉下拉刷新组件
|
9天前
|
前端开发 中间件 索引
鸿蒙开发:Navigation路由组件使用由繁入简
使用了插件和路由库之后,在每个Module下都会生成一个路由配置文件,以Module名字+RouterConfig为文件命名,此路由配置文件,也会在AbilityStage中,通过routerInitConfig方法进行自动配置。

热门文章

最新文章

下一篇
开通oss服务