目标概览图
组件(Component)
组件(Component)是界面搭建与显示的最小单位,组件根据功能可以分为以下五大类:基础组件、容器组件、媒体组件、绘制组件、画布组件。其中基础组件是视图层的基本组成单元。在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。
Web组件的生命周期
Web组件的状态主要包括:Controller绑定到Web组件、网页加载开始、网页加载进度、网页加载结束、页面即将可见等。
自定义组件的生命周期
自定义组件特点
- 可组合:允许开发者组合使用系统组件、及其属性和方法。
- 可重用:自定义组件可以被其他组件重用,并作为不同的实例在不同的父组件或容器中使用。
- 数据驱动UI更新:通过状态变量的改变,来驱动UI的刷新。
- 自定义组件通过“.”链式调用的形式设置通用样式
自定义组件的基本结构
- 自定义组件名、类名、函数名不能和系统组件名相同
- @Component装饰器仅能装饰struct关键字声明的数据结构。struct被@Component装饰后具备组件化的能力,需要实现build方法描述UI,一个struct只能被一个@Component装饰
- @Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中,最多可以使用@Entry装饰一个自定义组件
- @Entry装饰的自定义组件,其build()函数下的根节点唯一且必要,且必须为容器组件,其中ForEach禁止作为根节点
- @Component装饰的自定义组件,其build()函数下的根节点唯一且必要,可以为非容器组件,其中ForEach禁止作为根节点
@Component
struct MyComponent {
}
不建议在生命周期aboutToDisappear内使用async await,如果在生命周期的aboutToDisappear使用异步操作(Promise或者回调方法),自定义组件将被保留在Promise的闭包中,直到回调方法被执行完,这个行为阻止了自定义组件的垃圾回收
生命周期案例&自定义组件案例
// 推荐方式
import { HMNavigation,HMRouterMgr } from '@hadss/hmrouter'
// 测试数据源 model 一般是别的文件定义导入即可
class Model {
public value:string
constructor(value:string) {
this.value = value
}
}
@Component
export struct Demo{
@State message: string = '子组件初始化的State值';
/*
* build内部
* 不允许声明本地变量
* 不允许console.info
* 不允许本地作用域
* 不能调用没有用@Builder装饰的方法
* 不允许使用switch语法
* 如果需要使用条件判断,请使用if
* 不允许使用表达式
* 不允许直接改变状态变量
* */
build() {
// 子组件 根节点唯一且必要,可为非容器组件
Column(){
Text(this.message)
}
}
}
@Entry
@Component
struct Index {
// @State 声明的变量是组件外访问是不支持的 只能在组件内访问
@State message: string = 'Hello World';
@State count: number = 0
@State title: Model = new Model('我是鸿蒙啊');
@State list: Map<number, string> = new Map([[0, "vue"], [1, "react"], [3, "node"]]);
// 创建自定义组件的新实例后,在执行其build()函数之前执行。允许在aboutToAppear函数中改变状态变量,更改将在后续执行build()函数中生效
aboutToAppear(): void {
console.log("aboutToAppear---初始化")
}
// 当用户点击返回按钮时触发,仅@Entry装饰的自定义组件生效。返回true表示页面自己处理返回逻辑,不进行页面路由;返回false表示使用默认的路由返回逻辑,不设置返回值按照false处理
onBackPress():void{
console.log("onBackPress---当用户点击返回按钮时触发")
}
// 页面每次显示时触发一次,包括路由过程、应用进入前台等场景,仅@Entry装饰的自定义组件生效
onPageShow(): void {
console.log("onPageShow---页面显示")
}
// 页面每次隐藏时触发一次,包括路由过程、应用进入后台等场景,仅@Entry装饰的自定义组件生效
onPageHide(): void {
console.log("onPageHide---页面隐藏")
}
// aboutToDisappear函数在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定
aboutToDisappear(): void {
console.log("aboutToDisappear---页面销毁")
}
build() {
RelativeContainer() {
// 使用HMNavigation容器
HMNavigation({
navigationId: 'mainNavigation', options: {
// standardAnimator: HMDefaultGlobalAnimator.STANDARD_ANIMATOR,
// dialogAnimator: HMDefaultGlobalAnimator.DIALOG_ANIMATOR,
// modifier: modifier
}
}) {
Column(){
ForEach(Array.from(this.list.entries()), (item: [number, string]) => {
Text(`${item[0]}`).fontSize(30)
Text(`${item[1]}`).fontSize(30)
Divider()
})
}
// 自定义组件
Demo({message:'父组件初始化过来给子组件显示的内容,如果父组件没初始化就默认去取子组件的初始化值'})
// set/clear/delete 都是一样的可以操作的 Set 类型的 add/clear/delete一样可以操作
Button('向Map添加一项').onClick(() => {
this.list.set(4, "java");
})
Column() {
Text(`${this.title.value}`)
Text(`${this.count}`)
Text(this.message)
Button('更新状态数据').width(100).height(100).backgroundColor('#eeeeee').onClick(()=>{
this.message = 'hello 鸿蒙'
this.count++
this.title.value = this.title.value === '我是鸿蒙啊' ? '我准备更改model里面的数据' : '我是鸿蒙啊';
})
Button('NextPage').width(100).height(100).backgroundColor('#eeeeee').onClick(()=>{
HMRouterMgr.push({pageUrl: 'SendPage'})
})
}
.width('100%')
.height('100%')
}
}
.height('100%')
.width('100%')
}
}
@Builder装饰器:自定义构建函数
ArkUI提供了一种轻量的UI元素复用机制@Builder,该自定义组件内部UI结构固定,仅与使用方进行数据传递,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用
- @Builder通过按引用传递的方式传入参数,才会触发动态渲染UI,并且参数只能是一个
- @Builder如果传入的参数是两个或两个以上,不会触发动态渲染UI
- @Builder传入的参数中同时包含按值传递和按引用传递两种方式,不会触发动态渲染UI
- @Builder的参数必须按照对象字面量的形式,把所需要的属性一一传入,才会触发动态渲染UI
- 在@Builder方法内调用自定义组件或者其他@Builder方法,ArkUI提供$$作为按引用传递参数的范式
- 创建全局的@Builder方法,在Column里面使用overBuilder()方式调用,通过以对象字面量的形式传递参数,无论是简单类型还是复杂类型,值的改变都会引起UI界面的刷新
import { HMRouter, HMRouterMgr } from '@hadss/hmrouter'
@Builder function btnBuilder(str: string) {
Column() {
Text(`全局Builder接受的值: ${str} `)
}
}
// 模拟数据源一般放单独文件这里这是演示
class DataView {
name: string = '小明'
addr: string = '广东省深圳市南山区'
age: number = 30
}
@Builder function manBuilder(params: DataView) {
Row() {
Text(`姓名: ${params.name} `)
Text(`地址: ${params.addr} `)
Text(`年龄: ${params.age} `)
}
}
// 按引用传递参数时,如果在@Builder方法内调用自定义组件,ArkUI提供$$作为按引用传递参数的范式
@Builder function myBuilder($$: DataView) {
Row() {
Text(`姓名: ${$$.name} `)
HelloComponent({name: $$.name, addr:$$.addr, age:$$.age})
}
}
@Component
export struct HelloComponent {
@Prop name: string;
@Prop addr: string;
@Prop age: number;
build() {
Row() {
Text(`姓名:${this.name}`)
Text(`地址:${this.addr}`)
Text(`年龄:${this.age}`)
}
}
}
// 路由装饰器要在@Builder下面
@HMRouter({ pageUrl: 'SendPage' })
@Entry
@Component
export struct Send {
@State message: string = '我是第二个页面';
@State str: string = '描述全局的方法'
// 私有自定义构建函数
@Builder testBuilder(message: string) {
Column() {
Text(`接受的值: ${message} `)
}
}
build() {
RelativeContainer() {
Column(){
// 按值传递
// 私有@Builder 通过this.xxx 调用
this.testBuilder(this.message)
// 全局 @Builder 无需this调用
btnBuilder(this.str)
// 按引用传递
manBuilder(new DataView())
// 按引用传递参数时,如果在@Builder方法内调用自定义组件,ArkUI提供$$作为按引用传递参数的范式
myBuilder({name: '小花', addr:'广东省深圳市宝安区', age:28})
Column(){
Button('返回').width(100).height(100).backgroundColor('#eeeeee').onClick(()=>{
HMRouterMgr.pop()
})
}
}
}
.height('100%')
.width('100%')
}
}
@LocalBuilder装饰器: 维持组件父子关系
当开发者使用@Builder做引用数据传递时,会考虑组件的父子关系,使用了bind(this)之后,组件的父子关系和状态管理的父子关系并不一致。为了解决组件的父子关系和状态管理的父子关系保持一致,引入@LocalBuilder装饰器。@LocalBuilder拥有和局部@Builder相同的功能,且比局部@Builder能够更好的确定组件的父子关系和状态管理的父子关系。
- 允许在自定义组件内定义一个或多个@LocalBuilder方法,该方法被认为是该组件的私有、特殊类型的成员函数。
- 自定义构建函数可以在所属组件的build方法和其他自定义构建函数中调用,但不允许在组件外调用。
- 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递。
- @LocalBuilder只能在所属组件内声明,不允许全局声明。
- @LocalBuilder不能被内置装饰器和自定义装饰器使用。
- 自定义组件内的静态方法不能和@LocalBuilder一起使用
@LocalBuilder和局部@Builder使用区别
@Builder
方法引用传参时,为了改变this
指向,使用bind(this)
后,会导致组件的父子关系和状态管理的父子关系不一致,但是@LocalBuilder
是否使用bind(this)
,都不会改变组件的父子关系。
import { HMRouter, HMRouterMgr } from '@hadss/hmrouter'
// 模拟数据源一般放单独文件这里这是演示
class DataView {
name: string = '小明'
addr?: string = '广东省深圳市南山区'
age?: number = 30
}
// 子组件
@Component
export struct HelloComponent {
@Prop name: string;
@Prop addr: string;
@Prop age: number;
build() {
Row() {
Text(`姓名:${this.name}`)
}
}
}
// 路由装饰器要在@Builder下面
@HMRouter({ pageUrl: 'SendPage' })
@Entry
@Component
export struct Send {
@State message: string = '我是第二个页面';
@State str: string = '描述全局的方法'
// 按值传递 @LocalBuilder只能在所属组件内声明,不允许全局声明
@LocalBuilder localBuilderStr(message:string){
Column(){
Text(`${message}`)
}
}
@LocalBuilder localBuilderTest(params:DataView){
Column(){
Text(`姓名:${params.name}`)
}
}
// 按引用传递
@LocalBuilder quoteBuilder($$: DataView) {
Row() {
Column() {
Text(`quoteBuilder===${$$.name}`);
HelloComponent({ name: $$.name });
}
}
}
build() {
RelativeContainer() {
Column(){
// 按值传递
this.localBuilderStr(this.message)
this.localBuilderTest({name:"王二小"})
this.quoteBuilder({name:"王二小--引用方式"})
Column(){
Button('返回').width(100).height(100).backgroundColor('#eeeeee').onClick(()=>{
HMRouterMgr.pop()
})
}
}
}
.height('100%')
.width('100%')
}
}
@BuilderParam装饰器:引用@Builder函数
@BuilderParam用来装饰指向@Builder方法的变量(@BuilderParam是用来承接@Builder函数的)。开发者可以在初始化自定义组件时,使用不同的方式(如:参数修改、尾随闭包、借用箭头函数等)对@BuilderParam装饰的自定义构建函数进行传参赋值,在自定义组件内部通过调用@BuilderParam为组件增加特定的功能。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
- @BuilderParam装饰的方法只能被自定义构建函数(@Builder装饰的方法)初始化。如果在API 11中和@Require结合使用,则必须父组件构造传参。
- 使用所属自定义组件的自定义构建函数或者全局的自定义构建函数,在本地初始化@BuilderParam
- 用父组件自定义构建函数初始化子组件@BuilderParam装饰的方法
- @BuilderParam装饰的方法可以是有参数和无参数的两种形式,需与指向的@Builder方法类型匹配。@BuilderParam装饰的方法类型需要和@Builder方法类型一致。
- 在自定义组件中使用@BuilderParam装饰的属性时也可通过尾随闭包进行初始化。在初始化自定义组件时,组件后紧跟一个大括号“{}”形成尾随闭包场景。【此场景下自定义组件内有且仅有一个使用@BuilderParam装饰的属性,此场景下自定义组件不支持使用通用属性】
import { HMRouter, HMRouterMgr } from '@hadss/hmrouter'
// 模拟数据源一般放单独文件这里这是演示
class DataView {
name: string = '小明'
addr?: string = '广东省深圳市南山区'
age?: number = 30
}
@Builder function overBuilder($$: DataView) {
Text("有参数的匹配有参数的")
Text($$.name)
.backgroundColor(Color.Green)
}
// 子组件
@Component
export struct HelloComponent {
@Prop name: string;
@Prop addr: string;
@Prop age: number;
@Builder closerBuilder(){};
// 使用父组件的尾随闭包{}(@Builder装饰的方法)初始化子组件@BuilderParam
@BuilderParam closer: () => void = this.closerBuilder;
build() {
Row() {
Text(`姓名:${this.name}`)
// this.xxx 调用
this.closer()
}
}
}
// 路由装饰器要在@Builder下面
@HMRouter({ pageUrl: 'SendPage' })
@Entry
@Component
export struct Send {
@State message: string = '我是第二个页面';
@State str: string = '描述全局的方法'
@Builder customBuilder() {
Text('没有参数的匹配没有参数的')
};
// 无参数类型,指向的@Builder也是无参数类型
@BuilderParam customBuilderParam: () => void = this.customBuilder;
// 有参数类型,指向的@Builder也是有参数类型的方法
@BuilderParam customOverBuilderParam: ($$: DataView) => void = overBuilder;
build() {
RelativeContainer() {
Column(){
// 创建HelloComponent,在创建HelloComponent时,通过其后紧跟一个大括号“{}”形成尾随闭包
// 作为传递给子组件HelloComponent @BuilderParam closer: () => void的参数
HelloComponent({ name: this.message }) {
Column() {
Text("我是闭包产生的内容-尾随闭包初始化组件")
}.backgroundColor(Color.Yellow)
}
// this.xxx调用相关的 @BuilderParam
this.customBuilderParam()
this.customOverBuilderParam({name: '小花' } )
Column(){
Button('返回').width(100).height(100).backgroundColor('#eeeeee').onClick(()=>{
HMRouterMgr.pop()
})
}
}
}
.height('100%')
.width('100%')
}
}
wrapBuilder:封装全局@Builder
// 模板参数Args extends Object[]是需要包装的builder函数的参数列表
declare function wrapBuilder< Args extends Object[]>(builder: (...args: Args) => void): WrappedBuilder;
当开发者在一个struct内使用了多个全局@Builder函数,来实现UI的不同效果时,多个全局@Builder函数会使代码维护起来非常困难,并且页面不整洁。此时,开发者可以使用wrapBuilder来封装全局@Builder(核心作用-封装全局@Builder)
- wrapBuilder的参数返回WrappedBuilder对象(同时 WrappedBuilder对象也是一个模板类),实现全局@Builder可以进行赋值和传递
- wrapBuilder方法只能传入全局@Builder方法
- wrapBuilder方法返回的WrappedBuilder对象的builder属性方法只能在struct内部使用
- wrapBuilder必须传入被@Builder修饰的全局函数
- 重复定义wrapBuilder失效
import { HMRouter, HMRouterMgr } from '@hadss/hmrouter'
// 模拟数据源一般放单独文件这里这是演示
class DataView {
name: string = '小明'
addr?: string = '广东省深圳市南山区'
age?: number = 30
}
@Builder function testBuilderOne(value: string, size: number) {
Text(value)
.fontSize(size)
}
@Builder function testBuilderTwo(value: string, size: number) {
Text(value)
.fontSize(size)
.fontColor(Color.Pink)
}
// 引用传递
@Builder function overBuilder(param: DataView) {
Column(){
Text(`wrapBuildervalue:${param.name}`)
}
}
// 引用传递
const wBuilder: WrappedBuilder<[DataView]> = wrapBuilder(overBuilder);
// @Builder方法赋值给变量 wrapBuilder方法只能传入全局@Builder方法
// wrapBuilder方法返回的WrappedBuilder对象的builder属性方法只能在struct内部使用
let globalBuilder: WrappedBuilder<[string, number]> = wrapBuilder(testBuilderOne);
// 自定义组件Index使用ForEach来进行不同@Builder函数的渲染,可以使用builderArr声明的wrapBuilder数组进行不同@Builder函数效果体现
// 多个@Builder 合并 遍历初始化
const builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(testBuilderOne), wrapBuilder(testBuilderTwo)];
// 路由装饰器要在@Builder下面
@HMRouter({ pageUrl: 'SendPage' })
@Entry
@Component
export struct Send {
@State message: string = '我是第二个页面';
@State str: string = '描述全局的方法'
@Builder testBuilder() {
ForEach(builderArr, (item: WrappedBuilder<[string, number]>) => {
item.builder('Hello World', 30)
}
)
}
build() {
RelativeContainer() {
Column(){
wBuilder.builder({name: '小花'})
globalBuilder.builder(this.message, 50)
this.testBuilder()
Column(){
Button('返回').width(100).height(100).backgroundColor('#eeeeee').onClick(()=>{
HMRouterMgr.pop()
})
}
}
}
.height('100%')
.width('100%')
}
}
@Styles装饰器:定义组件重用样式 (封装样式用的)
@Styles装饰器可以将多条样式设置提炼成一个方法,直接在组件声明的位置调用。通过@Styles装饰器可以快速定义并复用自定义样式。
- 当前@Styles仅支持通用属性和通用事件。
- @Styles方法不支持参数
- @Styles可以定义在组件内或全局,在全局定义时需在方法名前面添加function关键字,组件内定义时则不需要添加function关键字。
- 只能在当前文件内使用,不支持export。如果想实现export功能,推荐使用AttributeModifier
- 可以在全局,也可以在组件内
- 定义在组件内的@Styles可以通过this访问组件的常量和状态变量,并可以在@Styles里通过事件来改变状态变量的值
- 组件内@Styles的优先级高于全局@Styles。框架优先找当前组件内的@Styles,如果找不到,则会全局查找
import { HMRouter, HMRouterMgr } from '@hadss/hmrouter'
// 全局
@Styles function globalFancy() {
.width(150)
.height(100)
.backgroundColor(Color.Pink)
}
// 路由装饰器要在@Builder下面
@HMRouter({ pageUrl: 'SendPage' })
@Entry
@Component
export struct Send {
@State message: string = '我是第二个页面';
@State heightValue: number = 100
// 组件内
@Styles fancy() {
.width(150)
.height(this.heightValue)
.backgroundColor(Color.Pink)
.onClick(() => {
this.heightValue = 200
})
}
build() {
RelativeContainer() {
Column(){
Column(){
Button('全局样式').width(100).height(100).backgroundColor('#eeeeee').globalFancy()
Button('组件内样式').width(100).height(100).backgroundColor('#eeeeee').fancy()
Button('返回').width(100).height(100).backgroundColor('#eeeeee').onClick(()=>{
HMRouterMgr.pop()
})
}
}
}
.height('100%')
.width('100%')
}
}
@Extend装饰器:定义扩展组件样式 (也可以抽取公共样式)
@Extend,用于扩展原生组件样式
// 语法
@Extend(UIComponentName) function functionName { ... }
- 和@Styles不同,@Extend仅支持在全局定义,不支持在组件内部定义
- 只能在当前文件内使用,不支持export,如果想实现export功能,推荐使用AttributeModifier
- 和@Styles不同,@Extend支持封装指定组件的私有属性、私有事件和自身定义的全局方法
- 和@Styles不同,@Extend装饰的方法支持参数,开发者可以在调用时传递参数,调用遵循TS方法传值调用
- @Extend装饰的方法的参数可以为function,作为Event事件的句柄
- @Extend的参数可以为状态变量,当状态变量改变时,UI可以正常的被刷新渲染
import { HMRouter, HMRouterMgr } from '@hadss/hmrouter'
// @Extend(Text)可以支持Text的私有属性fontColor
@Extend(Text) function fancyTest () {
.fontColor(Color.Red)
}
// superFancyText可以调用预定义的fancy 并且支持参数
@Extend(Text) function superFancyText(size:number) {
.fontSize(size)
.fancyTest()
}
// 作为Event事件的句柄
@Extend(Text) function handleClick(onClick: () => void) {
.backgroundColor(Color.Blue)
.onClick(onClick)
}
// 路由装饰器要在@Builder下面
@HMRouter({ pageUrl: 'SendPage' })
@Entry
@Component
export struct Send {
@State message: string = '我是第二个页面';
@State heightValue: number = 100
onClickHandler() {
this.message = '随便改点东西吧';
}
build() {
RelativeContainer() {
Column(){
Column(){
Text("随便写点内容").superFancyText(28)
// 事件句柄
Text(`${this.message}`).handleClick(() => {this.onClickHandler()})
Button('返回').width(100).height(100).backgroundColor('#eeeeee').onClick(()=>{
HMRouterMgr.pop()
})
}
}
}
.height('100%')
.width('100%')
}
}
stateStyles:多态样式
@Styles仅仅应用于静态页面的样式复用,stateStyles可以依据组件的内部状态的不同,快速设置不同样式
- stateStyles是属性方法,可以根据UI内部状态来设置样式
- stateStyles可以通过this绑定组件内的常规变量和状态变量
import { HMRouter, HMRouterMgr } from '@hadss/hmrouter'
// @Extend(Text)可以支持Text的私有属性fontColor
@Extend(Text) function fancyTest () {
.fontColor(Color.Red)
}
// superFancyText可以调用预定义的fancy 并且支持参数
@Extend(Text) function superFancyText(size:number) {
.fontSize(size)
.fancyTest()
}
// 作为Event事件的句柄
@Extend(Text) function handleClick(onClick: () => void) {
.backgroundColor(Color.Blue)
.onClick(onClick)
}
// 路由装饰器要在@Builder下面
@HMRouter({ pageUrl: 'SendPage' })
@Entry
@Component
export struct Send {
@State message: string = '我是第二个页面';
@State heightValue: number = 100
@Styles normalStyle() {
.backgroundColor(Color.Gray)
}
@Styles pressedStyle() {
.backgroundColor(Color.Red)
}
onClickHandler() {
this.message = '随便改点东西吧';
}
build() {
RelativeContainer() {
Column(){
Column(){
// @Styles和stateStyles联合使用
Button('按钮的事件不一样背景颜色随着改变')
.stateStyles({
normal: this.normalStyle,
pressed: this.pressedStyle
})
.margin(20)
// stateStyles 单独使用 基础用法
Button('按钮的事件不一样背景颜色随着改变')
.stateStyles({
focused: {
.backgroundColor('#ffffeef0')
},
pressed: {
.backgroundColor('#000000')
},
normal: {
.backgroundColor('#cccccc')
}
})
.margin(20)
Button('返回').width(100).height(100).backgroundColor('#eeeeee').onClick(()=>{
HMRouterMgr.pop()
})
}
}
}
.height('100%')
.width('100%')
}
}
@AnimatableExtend装饰器:定义可动画属性
// 语法
@AnimatableExtend(UIComponentName) function functionName(value: typeName) {
.propertyName(value)
}
@AnimatableExtend装饰器用于自定义可动画的属性方法,在这个属性方法中修改组件不可动画的属性。在动画执行过程时,通过逐帧回调函数修改不可动画属性值,让不可动画属性也能实现动画效果。也可通过逐帧回调函数每帧修改可动画属性的值,实现逐帧布局的效果。
-
@AnimatableExtend仅支持定义在全局,不支持在组件内部定义。
-
@AnimatableExtend定义的函数参数类型必须为number类型或者实现 AnimatableArithmetic接口的自定义类型。
-
@AnimatableExtend定义的函数体内只能调用@AnimatableExtend括号内组件的属性方法。
@AnimatableExtend(Text)
function animatableWidth(width: number) {
.width(width)
}
@Entry
@Component
struct AnimatablePropertyExample {
@State textWidth: number = 80;
build() {
Column() {
Text("AnimatableProperty")
.animatableWidth(this.textWidth)
.animation({ duration: 2000, curve: Curve.Ease })
Button("Play")
.onClick(() => {
this.textWidth = this.textWidth == 80 ? 160 : 80;
})
}.width("100%")
.padding(10)
}
}
@Require装饰器:校验构造传参
@Require是校验@Prop、@State、@Provide、@BuilderParam和普通变量(无状态装饰器修饰的变量)是否需要构造传参的一个装饰器
-
当@Require装饰器和@Prop、@State、@Provide、@BuilderParam、普通变量(无状态装饰器修饰的变量)结合使用时,在构造该自定义组件时,@Prop、@State、@Provide、@BuilderParam和普通变量(无状态装饰器修饰的变量)必须在构造时传参
-
@Require装饰器仅用于装饰struct内的@Prop、@State、@Provide、@BuilderParam和普通变量(无状态装饰器修饰的变量)