赞
踩
我们按照 UI范式中的指导 developer.huawei.com/consumer/cn…
将各部分都用一遍,写下如下的代码
// 通过builder的方式传递多个组件,作为自定义组件的一级子组件(即不包含容器组件,如Column) @Builder function ColumnChildren() { ForEach([1, 2, 3], (index: number) => { // 暂不支持lazyForEach的写法 Text('S' + index) .fontSize(30) .width(100) .height(100) .borderWidth(2) .offset({ x: 10, y: 20 }) }) } // 自定义可动画属性,这个只能是全局的 @AnimatableExtend(Text) function animatableFontSize(size: number) { .fontSize(size) } @Component struct CustomLayout { @Builder doNothingBuilder() { }; @BuilderParam builder: () => void = this.doNothingBuilder; @State startSize: number = 100; result: SizeResult = { width: 0, height: 0 }; // 第一步:计算各子组件的大小 onMeasureSize(selfLayoutInfo: GeometryInfo, children: Array<Measurable>, constraint: ConstraintSizeOptions) { let size = 100; children.forEach((child) => { let result: MeasureResult = child.measure({ minHeight: size, minWidth: size, maxWidth: size, maxHeight: size }) size += result.width / 2; }) this.result.width = 100; this.result.height = 400; return this.result; } // 第二步:放置各子组件的位置 onPlaceChildren(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions) { let startPos = 300; children.forEach((child) => { let pos = startPos - child.measureResult.height; child.layout({ x: pos, y: pos }) }) } build() { this.builder() } } @Builder function OuterBuilder() { Text('this is a outer builder text') } // Styles不支持参数 @Styles function OuterStyles() { .width(200) } // Extend 支持参数,可以访问组件的私有属性,支持状态变量,状态变量变化的时候UI也更新 @Extend(Text) function extendStyle(fontSize: number) { .fontColor(Color.Red) .fontSize(fontSize) } class Tmp { paramA1: string = '' } // 按引用传递参数 @Builder function overBuilderByRef(params: Tmp) { Row() { Text(`UseStateVarByReference: ${params.paramA1} `) } } @Builder function overBuilderByValue(paramA1: string) { Row() { Text(`UseStateVarByValue: ${paramA1} `) } } // WrapperBuilder用法 let globalBuilder: WrappedBuilder<[string]> = wrapBuilder(overBuilderByValue); @Component struct Child { // @Require 要求必传参数,可以是常规属性也可以是状态变量 @Require regular_value: string = 'Hello'; @Require @State state_value: string = "Hello"; @Require @Provide provide_value: string = "Hello"; @Builder doNothingBuilder() { }; // 使用自定义组件的自定义构建函数初始化@BuilderParam @BuilderParam customBuilderParam: () => void = this.doNothingBuilder; build() { Column() { this.customBuilderParam() } } } const pageStorage = new LocalStorage() @Entry({ routeName: 'StudyDeclareUIRouter', storage: pageStorage, }) @Component({ freezeWhenInactive: true }) export struct StudyDeclareUI { private myPrivateNum: number = 0 public myPublicNum: number = 0 @State myState: string = '' @State fontSize: number = 12 @State focusedColor: Color = Color.Red; normalColor: Color = Color.Green @Builder InnerBuilder() { Text('this is a inner builder text') } @Styles InnerStyles() { .width(200) } @Styles pressedStyle() { .backgroundColor(Color.Red) } myClickHandler() { console.log('you click the button') } // 只有被@Entry装饰的组件才可以调用页面的生命周期 onPageShow() { console.info('StudyDeclareUI onPageShow'); } // 只有被@Entry装饰的组件才可以调用页面的生命周期 onPageHide() { console.info('StudyDeclareUI onPageHide'); } // 只有被@Entry装饰的组件才可以调用页面的生命周期 onBackPress() { console.info('StudyDeclareUI onBackPress'); return true // 返回true表示页面自己处理返回逻辑,不进行页面路由;返回false表示使用默认的路由返回逻辑,不设置返回值按照false处理 } // 组件生命周期 aboutToAppear() { console.info('MyComponent aboutToAppear'); } // 组件生命周期 aboutToDisappear() { console.info('MyComponent aboutToDisappear'); } build() { Column() { Text('this is a text') .fontSize(14) .fontWeight(FontWeight.Bold) .onClick(() => { console.log('you click the text') }) Button('add counter') .onClick(this.myClickHandler.bind(this)) CustomLayout({ builder: ColumnChildren }) this.InnerBuilder() OuterBuilder() overBuilderByRef({ paramA1: 'hello' }) overBuilderByValue('world') Child({ regular_value: 'Hello', // 传递常规属性 state_value: 'Hello', // 传递状态变量 provide_value: 'Hello', // 传递提供的属性 customBuilderParam: this.InnerBuilder.bind(this) }) Child({ regular_value: 'Hello', // 传递常规属性 state_value: 'Hello', // 传递状态变量 provide_value: 'Hello', // 传递提供的属性 }) { Text('尾随闭包初始化子组件Child') } globalBuilder.builder('WrapperBuilder') Text('InnerStyles') .InnerStyles() .OuterStyles() .extendStyle(this.fontSize) .animatableFontSize(12) Button('clickMe') .height(100) .width(100) .stateStyles({ normal: { .backgroundColor(this.normalColor) }, focused: { .backgroundColor(this.focusedColor) }, // stateStyles可以和@Styles一起使用 pressed: this.pressedStyle }) .onClick(() => { this.focusedColor = Color.Pink }) .margin('30%') }.height('100%') } }
之后 使用IDE进行打包,可以在如下路径看到编译后的TS文件。同时我们也看到代码使用的序列化协议是protobuf
if (!("finalizeConstruction" in ViewPU.prototype)) { Reflect.set(ViewPU.prototype, "finalizeConstruction", () => { }); } interface StudyDeclareUI_Params { myPrivateNum?: number; myPublicNum?: number; myState?: string; fontSize?: number; focusedColor?: Color; normalColor?: Color; } interface Child_Params { regular_value?: string; state_value?: string; provide_value?: string; customBuilderParam?: () => void; } interface CustomLayout_Params { builder?: () => void; startSize?: number; result?: SizeResult; } /** * * StudyDeclareUI.ets * Created by unravel on 2024/4/30 * https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/3_1_u57fa_u672c_u8bed_u6cd5-0000001820999545-V5 * @abstract */ // 通过builder的方式传递多个组件,作为自定义组件的一级子组件(即不包含容器组件,如Column) function ColumnChildren(parent = null) { (parent ? parent : this).observeComponentCreation2((elmtId, isInitialRender) => { ForEach.create(); const forEachItemGenFunction = _item => { const index = _item; (parent ? parent : this).observeComponentCreation2((elmtId, isInitialRender) => { Text.create('S' + index); Text.fontSize(30); Text.width(100); Text.height(100); Text.borderWidth(2); Text.offset({ x: 10, y: 20 }); }, Text); Text.pop(); }; (parent ? parent : this).forEachUpdateFunction(elmtId, [1, 2, 3], forEachItemGenFunction); }, ForEach); ForEach.pop(); } // 自定义可动画属性,这个只能是全局的 function animatableFontSize(size: number, elmtId, isInitialRender, parent): void { if (isInitialRender) { Text.createAnimatableProperty("animatableFontSize", size, (size: number) => { ViewStackProcessor.StartGetAccessRecordingFor(elmtId); ViewStackProcessor.GetAndPushFrameNode("Text", elmtId); Text.fontSize(size); ViewStackProcessor.StopGetAccessRecording(); parent.finishUpdateFunc(elmtId); }); Text.fontSize(size); } else { Text.updateAnimatableProperty("animatableFontSize", size); } } class CustomLayout extends ViewPU { constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) { super(parent, __localStorage, elmtId, extraInfo); if (typeof paramsLambda === "function") { this.paramsGenerator_ = paramsLambda; } this.builder = this.doNothingBuilder; this.__startSize = new ObservedPropertySimplePU(100, this, "startSize"); this.result = { width: 0, height: 0 }; this.setInitiallyProvidedValue(params); this.finalizeConstruction(); } setInitiallyProvidedValue(params: CustomLayout_Params) { if (params.builder !== undefined) { this.builder = params.builder; } if (params.startSize !== undefined) { this.startSize = params.startSize; } if (params.result !== undefined) { this.result = params.result; } } updateStateVars(params: CustomLayout_Params) { } purgeVariableDependenciesOnElmtId(rmElmtId) { this.__startSize.purgeDependencyOnElmtId(rmElmtId); } aboutToBeDeleted() { this.__startSize.aboutToBeDeleted(); SubscriberManager.Get().delete(this.id__()); this.aboutToBeDeletedInternal(); } doNothingBuilder(parent = null) { } private __builder; private __startSize: ObservedPropertySimplePU<number>; get startSize() { return this.__startSize.get(); } set startSize(newValue: number) { this.__startSize.set(newValue); } private result: SizeResult; // 第一步:计算各子组件的大小 onMeasureSize(selfLayoutInfo: GeometryInfo, children: Array<Measurable>, constraint: ConstraintSizeOptions) { let size = 100; children.forEach((child) => { let result: MeasureResult = child.measure({ minHeight: size, minWidth: size, maxWidth: size, maxHeight: size }); size += result.width / 2; }); this.result.width = 100; this.result.height = 400; return this.result; } // 第二步:放置各子组件的位置 onPlaceChildren(selfLayoutInfo: GeometryInfo, children: Array<Layoutable>, constraint: ConstraintSizeOptions) { let startPos = 300; children.forEach((child) => { let pos = startPos - child.measureResult.height; child.layout({ x: pos, y: pos }); }); } initialRender() { this.builder.bind(this)(); } rerender() { this.updateDirtyElements(); } } function OuterBuilder(parent = null) { (parent ? parent : this).observeComponentCreation2((elmtId, isInitialRender) => { Text.create('this is a outer builder text'); }, Text); Text.pop(); } // Extend 支持参数,可以访问组件的私有属性,支持状态变量,状态变量变化的时候UI也更新 function __Text__extendStyle(fontSize: number): void { Text.fontColor(Color.Red); Text.fontSize(fontSize); } class Tmp { paramA1: string = ''; } // 按引用传递参数 function overBuilderByRef(params: Tmp, parent = null) { const __params__ = params; (parent ? parent : this).observeComponentCreation2((elmtId, isInitialRender, params = __params__) => { Row.create(); }, Row); (parent ? parent : this).observeComponentCreation2((elmtId, isInitialRender, params = __params__) => { Text.create(`UseStateVarByReference: ${params.paramA1} `); }, Text); Text.pop(); Row.pop(); } function overBuilderByValue(paramA1: string, parent = null) { const __paramA1__ = paramA1; (parent ? parent : this).observeComponentCreation2((elmtId, isInitialRender, paramA1 = __paramA1__) => { Row.create(); }, Row); (parent ? parent : this).observeComponentCreation2((elmtId, isInitialRender, paramA1 = __paramA1__) => { Text.create(`UseStateVarByValue: ${paramA1} `); }, Text); Text.pop(); Row.pop(); } // WrapperBuilder用法 let globalBuilder: WrappedBuilder<[ string ]> = wrapBuilder(overBuilderByValue); class Child extends ViewPU { constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) { super(parent, __localStorage, elmtId, extraInfo); if (typeof paramsLambda === "function") { this.paramsGenerator_ = paramsLambda; } this.regular_value = 'Hello'; this.__state_value = new ObservedPropertySimplePU("Hello", this, "state_value"); this.__provide_value = new ObservedPropertySimplePU("Hello", this, "provide_value"); this.addProvidedVar("provide_value", this.__provide_value, false); this.customBuilderParam = this.doNothingBuilder; this.setInitiallyProvidedValue(params); this.finalizeConstruction(); } setInitiallyProvidedValue(params: Child_Params) { if (params.regular_value !== undefined) { this.regular_value = params.regular_value; } if (params.state_value !== undefined) { this.state_value = params.state_value; } if (params.provide_value !== undefined) { this.provide_value = params.provide_value; } if (params.customBuilderParam !== undefined) { this.customBuilderParam = params.customBuilderParam; } } updateStateVars(params: Child_Params) { } purgeVariableDependenciesOnElmtId(rmElmtId) { this.__state_value.purgeDependencyOnElmtId(rmElmtId); this.__provide_value.purgeDependencyOnElmtId(rmElmtId); } aboutToBeDeleted() { this.__state_value.aboutToBeDeleted(); this.__provide_value.aboutToBeDeleted(); SubscriberManager.Get().delete(this.id__()); this.aboutToBeDeletedInternal(); } // @Require 要求必传参数,可以是常规属性也可以是状态变量 private regular_value: string; private __state_value: ObservedPropertySimplePU<string>; get state_value() { return this.__state_value.get(); } set state_value(newValue: string) { this.__state_value.set(newValue); } private __provide_value: ObservedPropertySimplePU<string>; get provide_value() { return this.__provide_value.get(); } set provide_value(newValue: string) { this.__provide_value.set(newValue); } doNothingBuilder(parent = null) { } // 使用自定义组件的自定义构建函数初始化@BuilderParam private __customBuilderParam; initialRender() { this.observeComponentCreation2((elmtId, isInitialRender) => { Column.create(); }, Column); this.customBuilderParam.bind(this)(); Column.pop(); } rerender() { this.updateDirtyElements(); } } const pageStorage = new LocalStorage(); export class StudyDeclareUI extends ViewPU { constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) { super(parent, __localStorage, elmtId, extraInfo); if (typeof paramsLambda === "function") { this.paramsGenerator_ = paramsLambda; } this.myPrivateNum = 0; this.myPublicNum = 0; this.__myState = new ObservedPropertySimplePU('', this, "myState"); this.__fontSize = new ObservedPropertySimplePU(12, this, "fontSize"); this.__focusedColor = new ObservedPropertySimplePU(Color.Red, this, "focusedColor"); this.normalColor = Color.Green; if (super["initAllowComponentFreeze"] && typeof super["initAllowComponentFreeze"] === "function") { super["initAllowComponentFreeze"](true); } this.setInitiallyProvidedValue(params); this.finalizeConstruction(); } setInitiallyProvidedValue(params: StudyDeclareUI_Params) { if (params.myPrivateNum !== undefined) { this.myPrivateNum = params.myPrivateNum; } if (params.myPublicNum !== undefined) { this.myPublicNum = params.myPublicNum; } if (params.myState !== undefined) { this.myState = params.myState; } if (params.fontSize !== undefined) { this.fontSize = params.fontSize; } if (params.focusedColor !== undefined) { this.focusedColor = params.focusedColor; } if (params.normalColor !== undefined) { this.normalColor = params.normalColor; } } updateStateVars(params: StudyDeclareUI_Params) { } purgeVariableDependenciesOnElmtId(rmElmtId) { this.__myState.purgeDependencyOnElmtId(rmElmtId); this.__fontSize.purgeDependencyOnElmtId(rmElmtId); this.__focusedColor.purgeDependencyOnElmtId(rmElmtId); } aboutToBeDeleted() { this.__myState.aboutToBeDeleted(); this.__fontSize.aboutToBeDeleted(); this.__focusedColor.aboutToBeDeleted(); SubscriberManager.Get().delete(this.id__()); this.aboutToBeDeletedInternal(); } private myPrivateNum: number; public myPublicNum: number; private __myState: ObservedPropertySimplePU<string>; get myState() { return this.__myState.get(); } set myState(newValue: string) { this.__myState.set(newValue); } private __fontSize: ObservedPropertySimplePU<number>; get fontSize() { return this.__fontSize.get(); } set fontSize(newValue: number) { this.__fontSize.set(newValue); } private __focusedColor: ObservedPropertySimplePU<Color>; get focusedColor() { return this.__focusedColor.get(); } set focusedColor(newValue: Color) { this.__focusedColor.set(newValue); } private normalColor: Color; InnerBuilder(parent = null) { this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create('this is a inner builder text'); }, Text); Text.pop(); } myClickHandler() { console.log('you click the button'); } // 只有被@Entry装饰的组件才可以调用页面的生命周期 onPageShow() { console.info('StudyDeclareUI onPageShow'); } // 只有被@Entry装饰的组件才可以调用页面的生命周期 onPageHide() { console.info('StudyDeclareUI onPageHide'); } // 只有被@Entry装饰的组件才可以调用页面的生命周期 onBackPress() { console.info('StudyDeclareUI onBackPress'); return true; // 返回true表示页面自己处理返回逻辑,不进行页面路由;返回false表示使用默认的路由返回逻辑,不设置返回值按照false处理 } // 组件生命周期 aboutToAppear() { console.info('MyComponent aboutToAppear'); } // 组件生命周期 aboutToDisappear() { console.info('MyComponent aboutToDisappear'); } initialRender() { this.observeComponentCreation2((elmtId, isInitialRender) => { Column.create(); Column.height('100%'); }, Column); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create('this is a text'); Text.fontSize(14); Text.fontWeight(FontWeight.Bold); Text.onClick(() => { console.log('you click the text'); }); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Button.createWithLabel('add counter'); Button.onClick(this.myClickHandler.bind(this)); }, Button); Button.pop(); { this.observeComponentCreation2((elmtId, isInitialRender) => { if (isInitialRender) { let componentCall = new CustomLayout(this, { builder: ColumnChildren }, undefined, elmtId, () => { }, { page: "entry/src/main/ets/pages/StudyDeclareUI.ets", line: 200 }); ViewPU.create(componentCall); let paramsLambda = () => { return { builder: ColumnChildren }; }; componentCall.paramsGenerator_ = paramsLambda; } else { this.updateStateVarsOfChildByElmtId(elmtId, {}); } }, { name: "CustomLayout" }); } this.InnerBuilder.bind(this)(); OuterBuilder.bind(this)(); overBuilderByRef.bind(this)(makeBuilderParameterProxy("overBuilderByRef", { paramA1: () => 'hello' })); overBuilderByValue.bind(this)('world'); { this.observeComponentCreation2((elmtId, isInitialRender) => { if (isInitialRender) { let componentCall = new Child(this, { regular_value: 'Hello', state_value: 'Hello', provide_value: 'Hello', customBuilderParam: this.InnerBuilder.bind(this) }, undefined, elmtId, () => { }, { page: "entry/src/main/ets/pages/StudyDeclareUI.ets", line: 205 }); ViewPU.create(componentCall); let paramsLambda = () => { return { regular_value: 'Hello', state_value: 'Hello', provide_value: 'Hello', customBuilderParam: this.InnerBuilder.bind(this) }; }; componentCall.paramsGenerator_ = paramsLambda; } else { this.updateStateVarsOfChildByElmtId(elmtId, {}); } }, { name: "Child" }); } { this.observeComponentCreation2((elmtId, isInitialRender) => { if (isInitialRender) { let componentCall = new Child(this, { regular_value: 'Hello', state_value: 'Hello', provide_value: 'Hello', customBuilderParam: () => { this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create('尾随闭包初始化子组件Child'); }, Text); Text.pop(); } }, undefined, elmtId, () => { }, { page: "entry/src/main/ets/pages/StudyDeclareUI.ets", line: 211 }); ViewPU.create(componentCall); let paramsLambda = () => { return { regular_value: 'Hello', state_value: 'Hello', provide_value: 'Hello', customBuilderParam: () => { this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create('尾随闭包初始化子组件Child'); }, Text); Text.pop(); } }; }; componentCall.paramsGenerator_ = paramsLambda; } else { this.updateStateVarsOfChildByElmtId(elmtId, {}); } }, { name: "Child" }); } globalBuilder.builder.bind(this)('WrapperBuilder'); this.observeComponentCreation2((elmtId, isInitialRender) => { Text.create('InnerStyles'); Text.width(200); Text.width(200); __Text__extendStyle(this.fontSize); animatableFontSize(12, elmtId, isInitialRender, this); }, Text); Text.pop(); this.observeComponentCreation2((elmtId, isInitialRender) => { Button.createWithLabel('clickMe'); Button.height(100); Button.width(100); ViewStackProcessor.visualState("normal"); Button.backgroundColor(this.normalColor); ViewStackProcessor.visualState("focused"); Button.backgroundColor(this.focusedColor); ViewStackProcessor.visualState("pressed"); Button.backgroundColor(Color.Red); ViewStackProcessor.visualState(); Button.onClick(() => { this.focusedColor = Color.Pink; }); Button.margin('30%'); }, Button); Button.pop(); Column.pop(); } rerender() { this.updateDirtyElements(); } static getEntryName(): string { return "StudyDeclareUI"; } } { let routeNameNode = 'StudyDeclareUIRouter'; if (routeNameNode != undefined) { registerNamedRoute(() => new StudyDeclareUI(undefined, {}, pageStorage), routeNameNode, { bundleName: "com.unravel.myapplication", moduleName: "entry", pagePath: "pages/StudyDeclareUI" }); } else { registerNamedRoute(() => new StudyDeclareUI(undefined, {}, pageStorage), "", { bundleName: "com.unravel.myapplication", moduleName: "entry", pagePath: "pages/StudyDeclareUI" }); } }
developer.huawei.com/consumer/cn…
全局@Builder转换成TS之后,原有函数有一些变化,多了一个parent参数,代表使用这个Builder的父组件
不同:自定义组件的observeComponentCreation2在create后,首次渲染是不会pop的,而@Builder每次渲染都会create、pop。后面我们再看自定义组件的转义代码
疑问:是不是好奇这里(parent ? parent : this) 如果不传parent,this指向谁?window吗?按照我们的理解谁调用builder它就指向谁
这里很重要的一点,function绑定了this,这下上面的疑问能够解答了,谁使用了这个Builder,谁就观察Builder的更新
不管是值传参的Builder还是引用传参的Builder,都绑定了this。
引用传参的Builder比值传参的Builder在调用上有更多的改造
1.创建了一个构建参数代理 makeBuilderParameterProxy
2.将原来的paramA1 string类型改造成了函数类型,函数体返回原来传递的字面量
简单看一下 makeBuilderParameterProxy。在 arkui_ace_engine 中
这个函数返回一个Proxy对象并对source对象进行封装,保证source的属性是一个函数或一个有get方法的对象,这主要是为了处理引用传递的值是@State以便更新UI
和全局Builder的实现很相似,只是不需要 (parent ? parent : this) 部分。因为this是固定已知的了
调用的地方也很相似。其实完全可以把组件内Builder当成全局Builder的简化版本
组件内Builder是全局Builder语法的简化版本,哪个组件使用Builder哪个组件监听负责刷新Builder
引用传参的Builder在转换成TS代码时,会对参数生成一个代理,并将引用参数的属性转换成函数,这个函数返回原参数的值,这样就能实现参数是State时,State驱动Builder UI刷新
developer.huawei.com/consumer/cn…
转换成TS之后,变成了any类型的__customBuilderParam变量,但这个变量并没有使用的地方。推测@BuilderParam也只是用于指示编译器校验@Builder参数
直接传递Builder函数的用法没有什么特别的,主要看一下尾随闭包是怎么包装的
可以看到尾随闭包被包装成了箭头函数,这样一次解决了this问题。我们由此也可以知道尾随闭包只能是()=>void形式的函数,即@BuilderParam的类型也是这样, 不能接收参数
BuilderParam主要提供编译期的参数类型检查,底层存储依然是个函数。主要的改变在于将尾随闭包转换成箭头函数,解决了this的绑定问题
developer.huawei.com/consumer/cn…
转换前后几乎没有变化,那我们看下wrapBuilder这个函数实现,在arkui_ace_engine中
这个函数非常简单,只是new了一个WrapperBuilder对象,这个对象持有了builder函数
用法也很简单,其实就是直接调用了对象持有的Builder。
底层系统组件,很多也使用了WrapperBuilder,比如ArkButtonComponent 在arkui_ace_engine中
wrapperBuilder使用传入的Builder生成一个对象,对象持有Builder函数。调用wrapperBuilder的builder方法就是直接调用Builder。wrapperBuilder另外一个作用是提供给编译器在编译期的类型检查
developer.huawei.com/consumer/cn…
全局Styles
组件内Styles
不管是全局Styles还是组件内Styles,转化成TS代码之后都没有了
直接将Styles函数里面的样式内联到了Ts代码中
eTS里面定义的全局和组件内Styles,在转换成TS时会被删除,将样式直接附加到组件上。就和没有定义过该Styles一样
至于为什么能够附加,是因为使用Styles的时候是在某个组件的上下文中,此时知道操作的是什么组件。又因为Style只能封装Common属性,所以不管什么组件,直接把XX拼接到Styles实现的点前面就行
developer.huawei.com/consumer/cn…
再把代码转换成TS的时候对Extend进行了重写,重写成了一个函数。因为此时知道扩展的哪个组件的样式,所以改写后的代码可以直接是Text.fontColor
使用的时候直接调用函数就行。因为知道是Text的样式扩展,所以类型问题在编译期就会暴露出来
Extend扩展样式在转换成TS代码后就变成了一个函数,编译器会在编译期做类型检查,保证这个Extend只能用在特定的组件上。
developer.huawei.com/consumer/cn…
针对不同的状态,是通过 ViewStackProcessor.visualState 来进行处理的
我们看一下 ViewStackProcessor.visualState。在arkui_ace_engine/frameworks/bridge/declarative_frontend/state_mgmt/src/lib/puv2_common/puv2_viewstack_processor.d.ts中
看一下C++代码 arkui_ace_engine/frameworks/bridge/declarative_frontend/view_stack_processor.h
developer.huawei.com/consumer/cn…
转换成TS之后,AnimatableFontSize对原有函数进行了修改,增加了 elmtId, isInitialRender,
parent三个参数。其中elemId代表做动画的组件,isInitialRender代表是否是首次渲染,parent代表组件的父组件
函数体内部实现逻辑
1.创建我们扩展的自定义动画属性animatableFontSize,并给它关联一个更新函数
2.每当一个VSync过来的时候就会调用这个更新函数
3.首次渲染是设置一下对应属性,之后渲染的时候每调用一次updateAnimatableProperty,对应的更新函数就会走一次
使用的地方就是一个正常的函数调用,将参数传入
AnimatableExtend装饰的函数,在转换成TS时会被改写,改写的函数会在组件上动态创建一个属性,属性名为AnimatableExtend装饰的函数名,同时会给这个属性绑定一个更新函数,每次调用装饰的函数时,绑定的更新函数就会一帧一帧的更新UI,达到动画的效果
developer.huawei.com/consumer/cn…
转换成TS之后只是去掉了@Require,其他的没什么变化。至于State和Provide变量变成了getter、setter是属于状态装饰器干的活,可以先不用关心
转换成TS之后使用的地方和没转换之前没有变化。所以@Require只是在编译的过程中生效,不会参与到最终产物
我们把其中一个属性注释掉不传递,此时IDE就编译报错。我们把提示信息拷贝,在developtools_ace_ets2bundle里面搜索
可以搜到两个地方 validateInitDecorator 和 validateInitParam,从名字可以看出一个是校验@Require装饰器,一个是校验参数初始值。我们简单看下validateInitDecorator的逻辑
它的判断逻辑是:如果参数被@Require装饰,而命名参数里面又没有传递这个参数,就报错
Require这个装饰器的作用是在编译期,用于指导编译器检查参数是否传递。检查的规则是:参数被@Require装饰了,却没通过命名参数方式传递过来,就会报错
参考资料
这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。
OpenHarmony北向、南向开发环境搭建
●ArkTS语言
●安装DevEco Studio
●运用你的第一个ArkTS应用
●ArkUI声明式UI开发
.……
●Stage模型入门
●网络管理
●数据管理
●电话服务
●分布式应用开发
●通知与窗口管理
●多媒体技术
●安全技能
●任务管理
●WebGL
●国际化开发
●应用测试
●DFX面向未来设计
●鸿蒙系统移植和裁剪定制
……
●ArkTS实践
●UIAbility应用
●网络案例
……
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。