学习UI规范基本语法
自定义组件
事件生命类型
ts
// 声明
submit :() => void = () =>{
this.num++
}
// 传递
Test1({num:this.num,submitArrow: this.submit })
//接收
submitArrow?: () => void
根节点容器怎么用
ts
@Entry
@Component
struct MyComponent {
build() {
// 根节点唯一且必要,必须为容器组件
Row() {
ChildComponent()
}
}
}
@Component
struct ChildComponent {
build() {
// 根节点唯一且必要,可为非容器组件
Image('test.jpg')
}
}
自定义组件生命周期
aboutToAppear组件即将出现时,在执行器build函数之前。
onDidBuild触发build函数执行之后回调。
aboutToDisappear函数在自定义组件析构销毁之前执行。
组件扩展
@Builder 自定义构建函数 @Builder装饰器用于封装可复用的UI结构
@LocalBuilder 维持组件关系
ts
// 返回child
@Component
struct Child {
label: string = 'Child';
@BuilderParam customBuilderParam: () => void;
build() {
Column() {
this.customBuilderParam()
}
}
}
@Entry
@Component
struct Parent {
label: string = 'Parent';
@Builder componentBuilder() {
Text(`${this.label}`)
}
// @LocalBuilder componentBuilder() {
// Text(`${this.label}`)
// }
build() {
Column() {
Child({ customBuilderParam: this.componentBuilder })
}
}
}
---------------------------------------------------------
// 返回parent
@Component
struct Child {
label: string = 'Child';
@BuilderParam customBuilderParam: () => void;
build() {
Column() {
this.customBuilderParam()
}
}
}
@Entry
@Component
struct Parent {
label: string = 'Parent';
// @Builder componentBuilder() {
// Text(`${this.label}`)
// }
@LocalBuilder componentBuilder() {
Text(`${this.label}`)
}
build() {
Column() {
Child({ customBuilderParam: this.componentBuilder })
}
}
}
@BuilderParam--@BuilderParam用于装饰指向@Builder方法的变量,开发者可以在初始化自定义组件时,使用不同的方式(如参数修改、尾随闭包、借用箭头函数等)对@BuilderParam装饰的自定义构建函数进行传参赋值。
@BuilderParam装饰的方法只能被自定义构建函数(@Builder装饰的方法)初始化。
使用@BuilderParam隔离多组件对@Builder跳转逻辑的调用
ts
@Component
struct Child {
@Builder
customBuilder() {
}
@BuilderParam customBuilderParam: () => void = this.customBuilder;
build() {
Column() {
this.customBuilderParam()
}
}
}
@Entry
@Component
struct Parent {
@Builder
componentBuilder() {
Text(`Parent builder `)
}
build() {
Column() {
Child({ customBuilderParam: this.componentBuilder })
}
}
}
wrapBuilder
ts
@Builder
function MyBuilder(value: string, size: number) {
Text(value)
.fontSize(size)
}
@Builder
function YourBuilder(value: string, size: number) {
Text(value)
.fontSize(size)
.fontColor(Color.Pink)
}
const builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)];
@Entry
@Component
struct Index {
@Builder
testBuilder() {
ForEach(builderArr, (item: WrappedBuilder<[string, number]>) => {
item.builder('Hello World', 30)
}
)
}
build() {
Row() {
Column() {
this.testBuilder()
}
.width('100%')
}
.height('100%')
}
}
一些装饰器
@Styles自定义组件重用样式
@Expend组件扩展示样式
stateStyles:多态样式
ts
@Component
struct Child {
label: string = 'Child';
@BuilderParam customBuilderParam: () => void;
build() {
Column() {
this.customBuilderParam()
}
}
}
@Extend(Text)
function fancy() {
.fontColor(Color.White)
}
@Entry
@Component
struct Parent {
@Styles
red() {
.width(200)
.background(Color.Red)
}
label: string = 'Parent';
// @Builder componentBuilder() {
// Text(`${this.label}`)
// }
@LocalBuilder componentBuilder() {
Text(`${this.label}`)
}
build() {
Column() {
Text('1234').red().fancy()
Child({ customBuilderParam: this.componentBuilder })
Button('Button1')
.stateStyles({
focused: {
.backgroundColor('#ffffeef0')
},
pressed: {
.backgroundColor(Color.Red)
},
normal: {
.backgroundColor('#ff2787d9')
}
})
.margin(20)
}
}
}
学习UI范式装填管理V1
@State
@Prop
@Link
@Provide @Consume
@Observed @ObjectLink
@ObjectLink接收@State传递built-in类型和普通class对象,可以观察其API调用和第一层变化,无需额外添加@Observed装饰。因为@State等状态变量装饰器,会给对象(外层对象)添加一层"代理"包装,其功能等同于添加@Observed装饰。
ts
@Observed
class Book {
name:string;
count:number
constructor(name:string,count:number) {
this.name = name
this.count= count
}
}
@Observed
class Bag {
book:Book;
constructor(book:Book) {
this.book = book
}
}
@Entry
@Component
struct Index {
@Provide('aa') a:string = 'provide'
@State book:Book = new Book('小红书',12)
@State bag: Bag = new Bag(new Book('JS',12));
build() {
Column() {
Text(this.book.name)
Text(this.bag.book.name)
Test1({book:this.book})
Button('change book.name')
.width(320)
.margin(10)
.onClick(() => {
this.book = new Book('咸鱼',13)
// this.book.name = 'C++';
// this.book.count++;
// this.bag.book.name = 'TS';
// this.bag.book.count ++
})
Divider()
Test2({book:this.bag.book})
}
}
}
@Component
struct Test1 {
@ObjectLink book:Book
build() {
Column() {
Text(this.book.count.toString())
// Test2()
Button('改变book').onClick((event: ClickEvent) => {
this.book.count++
})
}
}
}
@Component
struct Test2 {
@Consume('aa') a:string
@ObjectLink book:Book
build() {
Column() {
Text('test2----'+ this.book.count)
Button('++').onClick((event: ClickEvent) => {
this.book.count++
})
}
}
}
LocalStorage 页面级UI状态存储 LocalStorageProp、LocalStorageLink
ts
class Data {
code: number;
constructor(code: number) {
this.code = code;
}
}
// 创建新实例并使用给定对象初始化
let para: Record<string, number> = { 'PropA': 11 };
let storage: LocalStorage = new LocalStorage(para);
storage.setOrCreate('PropB', new Data(50));
@Component
struct Child {
// @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定
@LocalStorageLink('PropA') childLinkNumber: number = 1;
// @LocalStorageLink变量装饰器与LocalStorage中的'PropB'属性建立双向绑定
@LocalStorageLink('PropB') childLinkObject: Data = new Data(0);
build() {
Column({ space: 15 }) {
// 更改将同步至LocalStorage中的'PropA'以及Parent.parentLinkNumber
Button(`Child from LocalStorage ${this.childLinkNumber}`)
.onClick(() => {
this.childLinkNumber += 1;
})
// 更改将同步至LocalStorage中的'PropB'以及Parent.parentLinkObject.code
Button(`Child from LocalStorage ${this.childLinkObject.code}`)
.onClick(() => {
this.childLinkObject.code += 1;
})
}
}
}
// 使LocalStorage可从@Component组件访问
@Entry(storage)
@Component
struct Parent {
// @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定
@LocalStorageLink('PropA') parentLinkNumber: number = 1;
// @LocalStorageLink变量装饰器与LocalStorage中的'PropB'属性建立双向绑定
@LocalStorageLink('PropB') parentLinkObject: Data = new Data(0);
build() {
Column({ space: 15 }) {
// 由于LocalStorage中PropA已经被初始化,因此this.parentLinkNumber的值为47
Button(`Parent from LocalStorage ${this.parentLinkNumber}`)
.onClick(() => {
this.parentLinkNumber += 1;
})
// 由于LocalStorage中PropB已经被初始化,因此this.parentLinkObject.code的值为50
Button(`Parent from LocalStorage ${this.parentLinkObject.code}`)
.onClick(() => {
this.parentLinkObject.code += 1;
})
// @Component子组件自动获得对Parent LocalStorage实例的访问权限。
Child()
}
}
}
// 应用全局的UI状态
AppStorage
@StoragePop单向
@StorageLink双向
不会通知UI刷新
ts
AppStorage.set<number>('propA', 100);
ts
class Data {
code: number;
constructor(code: number) {
this.code = code;
}
}
AppStorage.setOrCreate('propA', 47);
AppStorage.setOrCreate('propB', new Data(50));
let storage = new LocalStorage();
storage.setOrCreate('linkA', 48);
storage.setOrCreate('linkB', new Data(100));
@Entry()
@Component
struct Index {
@StorageLink('propA') storageLink: number = 1;
@StorageProp('propA') storageProp: number = 1;
@StorageLink('propB') storageLinkObject: Data = new Data(1);
@StorageProp('propB') storagePropObject: Data = new Data(1);
build() {
Column({ space: 20 }) {
// @StorageLink与AppStorage建立双向联系,更改数据会同步回AppStorage中key为'propA'的值
Text(`storageLink ${this.storageLink}`)
.onClick(() => {
this.storageLink += 1;
})
// @StorageProp与AppStorage建立单向联系,更改数据不会同步回AppStorage中key为'propA'的值
// 但能被AppStorage的set/setorCreate更新值
Text(`storageProp ${this.storageProp}`)
.onClick(() => {
this.storageProp += 1;
})
// AppStorage的API虽然能获取值,但是不具有刷新UI的能力,日志能看到数值更改
// 依赖@StorageLink/@StorageProp才能建立起与自定义组件的联系,刷新UI
Text(`change by AppStorag11e: ${AppStorage.get<number>('propA')}`)
.onClick(() => {
console.info(`Appstorage.get: ${AppStorage.get<number>('propA')}`);
AppStorage.set<number>('propA', 100);
})
Text(`storageLinkObject ${this.storageLinkObject.code}`)
.onClick(() => {
this.storageLinkObject.code += 1;
})
Text(`storagePropObject ${this.storagePropObject.code}`)
.onClick(() => {
this.storagePropObject.code += 1;
})
}
}
}
// 持久话存储UI状态
PersisitentStorage
PersistentStorage.persistProp('aProp', 47);
ts
PersistentStorage.persistProp('aProp', 47);
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@StorageLink('aProp') aProp: number = 48;
build() {
Row() {
Column() {
Text(this.message)
// 应用退出时会保存当前结果。重新启动后,会显示上一次的保存结果
// 未修改时默认值为47
Text(`${this.aProp}`)
.onClick(() => {
this.aProp += 1;
})
}
}
}
}
@Component
Environment 设备环境查询
ts
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage) {
windowStage.loadContent('pages/Index');
let window = windowStage.getMainWindow();
window.then(window => {
let uiContext = window.getUIContext();
uiContext.runScopedTask(() => {
Environment.envProp('languageCode', 'en');
});
});
}
}
@Watch
ts
@Component
struct TotalView {
@Prop @Watch('onCountUpdated') count: number = 0;
@State total: number = 0;
// @Watch 回调
onCountUpdated(propName: string): void {
this.total += this.count;
}
build() {
Text(`Total: ${this.total}`)
}
}
@Entry
@Component
struct CountModifier {
@State count: number = 0;
build() {
Column() {
Button('add to basket')
.onClick(() => {
this.count++
})
TotalView({ count: this.count })
}
}
}
系统组件双向同步 **$$运算符为系统组件提供TS变量的引用,使得TS变量和系统组件的内部状态保持同步。** ```ts @Entry @Component struct Index { @State text: string = ''; controller: TextInputController = new TextInputController(); build() { Column({ space: 20 }) { Text(this.text) TextInput({ text: $$this.text, placeholder: 'input your word...', controller: this.controller }) .placeholderColor(Color.Grey) .placeholderFont({ size: 14, weight: 400 }) .caretColor(Color.Blue) .width(300) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } } ``` @Track class对象属性级更新---------避免无用渲染 @Track是class对象的属性装饰器。当一个class对象是状态变量时,@Track装饰的属性发生变化,只会触发该属性关联的UI更新;如果class类中使用了@Track装饰器,则未被@Track装饰器装饰的属性不能在UI中使用,如果使用,会发生运行时报错。 #### 学习UI范式装填管理V2 @Local @Param @Once @Event @provider @Consumer @ObServedV2 @Trace @Computed @Monitor @ReusableV2 @ComponentV2 AppStorageV2 #### 学习UI范式渲染控制