做网站推广哪些,跨境电商平台企业,js网站评论框,如何做好网站建设的关键前提#xff1a;基于官网3.1/4.0文档。参考官网文档 基于Android开发体系来进行比较和思考。#xff08;或有偏颇#xff0c;自行斟酌#xff09; 吐槽#xff1a;官网上的案例只有代码和文档解释#xff0c;没有可以直接运行查看效果的模拟器#xff0c;这一点上#… 前提基于官网3.1/4.0文档。参考官网文档 基于Android开发体系来进行比较和思考。或有偏颇自行斟酌 吐槽官网上的案例只有代码和文档解释没有可以直接运行查看效果的模拟器这一点上Jetpack Compose是有的。 基本语法
1.结构 上面是官网上面的图从结构来看类似Jetpack Compose。 通过注解的方式来定义组件这里给命名为了“装饰器”。 需要注意的是State表示组件中的状态变量状态变量变化会触发UI刷新。类比livedata
2.引用的方式
// $r形式引入应用资源可应用于多语言场景
Text($r(app.string.title_value))
Image(this.imagePath)
Image(https:// this.imageUrl)
Text(count: ${this.count})// 这种方式在react中较为常见应该是ts的写法引用本地资源的方式是$r(app.string.title_value)。感觉稍显复杂了
3.this作用域
fn () {console.info(counter: ${this.counter})this.counter
}
Button(add counter).onClick(this.fn)可以看到this作用域是整个文件而不是Android中的闭包作用域。
4.组件
Component
struct MyComponent {build() {}
}自定义组件标准范式如上。加上注解Entry装饰的自定义组件将作为UI页面的入口。这句话比较难理解可以认为是export之类的用法一个文件只有一个exportReact项目中的特点。 Entry可以接受一个可选的LocalStorage的参数。——这点类似于Android中的bundle用来进行UI页面的数据传递。不确定该LocalStorage是否是livedata特点。 build
//不能在build里声明变量需要放在build外。
build() {// 反例不允许声明本地变量let a: number 1;
}//不允许在UI描述里直接使用console.info但允许在方法或者函数里使用——可以理解为build{}是渲染作用域不要添加打印
build() {// 反例不允许console.infoconsole.info(print debug log);
}//不允许创建本地的作用域——既然是渲染作用域那就不必要再添加作用域直接堆砌组件即可。组件作用域里面可以调用方法
build() {// 反例不允许本地作用域{...}
}不允许switch语法如果需要使用条件判断请使用if——这一点甚是奇怪都是判断语句还做不一样的差异对待
build() {Column() {// 反例不允许使用switch语法switch (expression) {case 1:Text(...)break;case 2:Image(...)break;default:Text(...)break;}}
}build() {Column() {// 反例不允许使用表达式——实际上这种写法在React中很常见不确定知道jetpack compose是否如此设计(this.aVar 10) ? Text(...) : Image(...)}
}生命周期 页面生命周期即被Entry装饰的组件生命周期提供以下生命周期接口 onPageShow页面每次显示时触发一次包括路由过程、应用进入前台等场景仅Entry装饰的自定义组件生效。 onPageHide页面每次隐藏时触发一次包括路由过程、应用进入后台等场景仅Entry装饰的自定义组件生效。 onBackPress当用户点击返回按钮时触发仅Entry装饰的自定义组件生效。 组件生命周期即一般用Component装饰的自定义组件的生命周期提供以下生命周期接口 aboutToAppear组件即将出现时回调该接口具体时机为在创建自定义组件的新实例后在执行其build()函数之前执行。 aboutToDisappear在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量特别是Link变量的修改可能会导致应用程序行为不稳定。 生命周期相较于Android是做了减法。不确定是否有页面栈的设计模式譬如说栈顶复用之类以及由此进行的bundle数据传递。
组件的销毁 组件的销毁是从组件树上直接摘下子树所以先调用父组件的aboutToDisappear再调用子组件的aboutToDisappear然后执行初始化新页面的生命周期流程。 以下是官方示例
// Index.ets
import router from ohos.router;Entry
Component
struct MyComponent {State showChild: boolean true;// 只有被Entry装饰的组件才可以调用页面的生命周期onPageShow() {console.info(Index onPageShow);}// 只有被Entry装饰的组件才可以调用页面的生命周期onPageHide() {console.info(Index onPageHide);}// 只有被Entry装饰的组件才可以调用页面的生命周期onBackPress() {console.info(Index onBackPress);}// 组件生命周期aboutToAppear() {console.info(MyComponent aboutToAppear);}// 组件生命周期aboutToDisappear() {console.info(MyComponent aboutToDisappear);}build() {Column() {// this.showChild为true创建Child子组件执行Child aboutToAppearif (this.showChild) {Child()}// this.showChild为false删除Child子组件执行Child aboutToDisappearButton(delete Child).onClick(() {this.showChild false;})// push到Page2页面执行onPageHideButton(push to next page).onClick(() {router.pushUrl({ url: pages/Page2 });})}}
}Component
struct Child {State title: string Hello World;// 组件生命周期aboutToDisappear() {console.info([lifeCycle] Child aboutToDisappear)}// 组件生命周期aboutToAppear() {console.info([lifeCycle] Child aboutToAppear)}build() {Text(this.title).fontSize(50).onClick(() {this.title Hello ArkUI;})}
}Builder作用
用来自定义构建函数它就是个标识符。 ArkUI还提供了一种更轻量的UI元素复用机制BuilderBuilder所装饰的函数遵循build()函数语法规则开发者可以将重复使用的UI元素抽象成一个方法在build方法里调用。 所以这到底是个什么作用有没有这个的区别是什么在build方法里面调用是指什么有没有对比的案例 待解答 //定义私有组件
Builder MyBuilderFunction(){ ... }
//调用私有组件
this.MyBuilderFunction()//定义全局组件
Builder function MyGlobalBuilderFunction(){ ... }
//调用全局组件
MyGlobalBuilderFunction()可以看到这里的function的作用是将组件定义为全局的修饰符而并不是函数的声明修饰符。这点容易让人误解
值传递和引用传递
引用传递 ArkUI提供$$作为按引用传递参数的范式 吐槽这个双美元符号作为范式真的比较繁琐 ABuilder( $$ : { paramA1: string, paramB1 : string } );Builder function ABuilder($$: { paramA1: string }) {Row() {Text(UseStateVarByReference: ${$$.paramA1} )}
}
Entry
Component
struct Parent {State label: string Hello;build() {Column() {// 在Parent组件中调用ABuilder的时候将this.label引用传递给ABuilderABuilder({ paramA1: this.label })Button(Click me).onClick(() {// 点击“Click me”后UI从“Hello”刷新为“ArkUI”this.label ArkUI;})}}
}和TS使用方式是类似的只不过这里的引用方式传值是带有状态的即指向的引用值发生变化也会引发Builder方法内的UI刷新。
值传递
Builder function ABuilder(paramA1: string) {//注意这个基本数据类型是小写的string与TS一致Row() {Text(UseStateVarByValue: ${paramA1} )}
}
Entry
Component
struct Parent {State label: string Hello;build() {Column() {ABuilder(this.label)}}
}可以看到很明显不是使用范式来进行参数的传递而是场景的传参方式。这种值传递的方式和引用方式的传递的区别在于前者值的变更不会触发Builder组件的UI刷新。
BuilderParam
作用是什么 当开发者创建了自定义组件并想对该组件添加特定功能时例如在自定义组件中添加一个点击跳转操作。若直接在组件内嵌入事件方法将会导致所有引入该自定义组件的地方均增加了该功能。为解决此问题ArkUI引入了BuilderParam装饰器BuilderParam用来装饰指向Builder方法的变量开发者可在初始化自定义组件时对此属性进行赋值为自定义组件增加特定的功能。该装饰器用于声明任意UI描述的一个元素类似slot占位符。 由此看来其实类似于Kotlin中的扩展函数。注意扩展函数是扩展“函数”不能扩展成员变量。暂不能确认这里是否可以扩展成员变量 如何用? BuilderParam装饰的方法只能被自定义构建函数Builder装饰的方法初始化。 案例
Component
struct Child {BuilderParam aBuilder0: () void;build() {Column() {this.aBuilder0()}}
}Entry
Component
struct Parent {Builder componentBuilder() {Text(Parent builder )}build() {Column() {Child({ aBuilder0: this.componentBuilder })}}
}官方举的案例硬是没看懂它的实际用途。——实际上它类似于Android中addView(View方法中的参数View你可以丢进去LinearLayout、Button等等它就是个抽象的占位参数。
Styles
是什么* 样式装饰器 做什么用 样式的集合可以用来重用。类似于Android styles文件中定义的style。 怎么用
// 定义在全局的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仍旧是类似于Builder一样分为私有和全局定义加上function修饰就是全局Styles里面包含了对点击事件的封装也有可能有其他事件譬如触摸事件重点是它包含了“事件”而不单单是通常意义上的样式引用方式直接就是通过链式的.操作不确定后续的style包含组件本身的属性是否会覆盖Style的属性
Extend
是什么 Styles用于样式的扩展在Styles的基础上我们提供了Extend用于扩展原生组件样式——也就是Styles为自定义组件扩展样式而这个Extend是为原生组件扩展样式譬如Text就是原生组件 为什么要区分两种标识符 什么作用 作用是和Styles一样的不过它可以传参Styles的函数时不可以传参的。这意味着它更灵活。但是它只能在组件内部定义而不能全局定义也就是不能使用function。当然并没有解释为什么不可以估计与设计逻辑冲突有关 怎么用
Entry
Component
struct FancyUse {State label: string Hello Worldbuild() {Row({ space: 10 }) {Text(${this.label}).fontStyle(FontStyle.Italic).fontWeight(100).backgroundColor(Color.Blue)Text(${this.label}).fontStyle(FontStyle.Italic).fontWeight(200).backgroundColor(Color.Pink)Text(${this.label}).fontStyle(FontStyle.Italic).fontWeight(300).backgroundColor(Color.Orange)}.margin(20%)}
}上面是一种通用写法一种样式写了三次那么优化之后如下
Extend(Text) function fancyText(weightValue: number, color: Color) {.fontStyle(FontStyle.Italic).fontWeight(weightValue).backgroundColor(color)
}Entry
Component
struct FancyUse {State label: string Hello Worldbuild() {Row({ space: 10 }) {Text(${this.label}).fancyText(100, Color.Blue)Text(${this.label}).fancyText(200, Color.Pink)Text(${this.label}).fancyText(300, Color.Orange)}.margin(20%)}
}很明显封装性更好可读性更强了。
stateStyles
是什么 状态样式这样不好理解。关于组件状态的回调——这里理解可能比较清晰。具体见下面的案例
怎么用
Entry
Component
struct CompWithInlineStateStyles {State focusedColor: Color Color.Red;normalColor: Color Color.Greenbuild() {Column() {Button(clickMe).height(100).width(100).stateStyles({normal: {.backgroundColor(this.normalColor)},focused: {.backgroundColor(this.focusedColor)}}).onClick(() {this.focusedColor Color.Pink}).margin(30%)}}
}focused获焦态。 normal正常态。 pressed按压态。 disabled不可用态。 因此它至少上面四种状态可供回调设置样式。——不确定是否可以在这个状态回调方法进行其他逻辑处理。可能不可以因为是使用的.方法的方式