目录
样式复用
@Styles方法
@Extend方法
组件编程在使用过程中有很多技巧,在这里分享样式复用技巧和UI结构复用技巧。
样式复用
我们观察下面的代码,在代码中很多重复行的代码,如:
Image 的 .width(30).height(30) 是重复的 Button的 .fontSize(25).width(150).height(65).backgroundColor(Color.Green)是重复的 Text 的 .fontSize(20).fontColor(Color.White).fontWeight(500) 是重复的
@Entry
@Component
struct customStyle {
@State isOn: boolean = false;
@State isDel: boolean = false;
build() {
Column({ space: 10 }) {
Button({ type: ButtonType.Capsule, stateEffect: true }) {
Row({ space: 10 }) {
Image($r('app.media.icon_new_folder'))
.width(30)
.height(30)
Text('新建文件')
.fontSize(20)
.fontColor(Color.White)
.fontWeight(500)
}
}
.fontSize(25)
.width(150)
.height(65)
.backgroundColor(Color.Green)
.onClick(() => {
console.log('我准备开始建立文件夹');
})
Button({ type: ButtonType.Capsule, stateEffect: true }) {
Row({ space: 10 }) {
Image($r('app.media.icon_new_folder'))
.width(30)
.height(30)
Text('新建文件')
.fontSize(20)
.fontColor(Color.White)
.fontWeight(500)
}
}
.fontSize(25)
.width(150)
.height(65)
.backgroundColor(Color.Green)
.onClick(() => {
console.log('我准备开始建立文件夹');
})
}
.width('100%')
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
@Extend(Image) function consumeImgStyle() {
.width(30)
.height(30)
}
@Extend(Button) function consumeButtonStyle() {
.fontSize(25)
.width(150)
.height(65)
}
@Extend(Text) function consumeBTextStyle() {
.fontSize(20)
.fontColor(Color.White)
.fontWeight(500)
}
当多个组件具有相同的样式时,若每个组件都单独设置,将会有大量的重复代码。为避免重复代码,开发者可使用@Styles或者@Extend装饰器将多条样式设置提炼成一个方法,然后直接在各组件声明的位置进行调用,这样就能完成样式的复用。
@Styles方法
@Styles方法可定义在组件内或者全局。
- 1. 组件内定义的@Styles方法只能在当前组件中使用,全局的@Styles方法目前只允许在当前的.ets文件中使用
- 2. 组件内定义@Styles方法时不需要使用function关键字,全局的@Styles方法需要使用function关键字
- 3. @Styles方法中只能包含通用属性方法和通用事件方法,例如在上面的代码中 fontSize(20).fontColor(Color.White).fontWeight(500)也是重复的,但这不是通用属性。可以定义的只能是通用属性。
- 4. @Styles方法不支持参数
- 5. @Styles方法可以用在任意类型的组件上。注意下面的@Extend则是使用在定制化组件上。
将上面重复的样式代码分别提取到各自定义的@Style方法中,直接使用@Style方法
定义格式如下。
@Styles定义在Struct结构体内部
===============================================================================
@Styles consumeImgStyle(){
.width(30)
.height(30)
}
@Styles consumeButtonStyle(){
.width(150)
.height(65)
.backgroundColor(Color.Green)
}
@Styles定义在同一个ets文件中的Struct结构体外部,必须加上 function 关键字
===============================================================================
@Styles function globalConsumeImgStyle() {
.width(30)
.height(30)
}
@Styles function globalConsumeButtonStyle() {
.width(150)
.height(65)
.backgroundColor(Color.Green)
}
将重复样式代码提取之后,直接使用提取后的方法,使用@Styles方法之后代码。
@Entry
@Component
struct customStyle {
@State isOn: boolean = false;
@State isDel: boolean = false;
build() {
Column({ space: 10 }) {
Button({ type: ButtonType.Capsule, stateEffect: true }) {
Row({ space: 10 }) {
Image($r('app.media.icon_delete'))
.consumeImgStyle()
Text('删除文件')
.fontSize(20)
.fontColor(Color.White)
.fontWeight(500)
}
}
.fontSize(25)
.width(150)
.height(65)
Button({ type: ButtonType.Capsule, stateEffect: true }) {
Row({ space: 10 }) {
Image($r('app.media.icon_new_folder'))
.consumeImgStyle()
Text('新建文件')
.fontSize(20)
.fontColor(Color.White)
.fontWeight(500)
}
}
.consumeButtonStyle()
.fontSize(25)
.onClick(() => {
console.log('我准备开始建立文件夹');
})
}
.width('100%')
.height("100%")
.justifyContent(FlexAlign.Center)
}
@Styles consumeImgStyle(){
.width(30)
.height(30)
}
@Styles consumeButtonStyle(){
.width(150)
.height(65)
.backgroundColor(Color.Green)
}
}
定义全局使用的@Styles方法需要加 function
======================================================
@Styles function globalConsumeImgStyle() {
.width(30)
.height(30)
}
@Styles function globalConsumeButtonStyle() {
.width(150)
.height(65)
.backgroundColor(Color.Green)
}
@Extend方法
@Extend装饰的方法同样可用于组件样式的复用,与@Styles不同的是:
- @Extend方法只能定义在全局,使用范围目前只限于当前的.ets文件
- @Extend方法只能用于指定类型的组件,如Button组件
- @Extend方法可包含指定组件的专有属性方法和专有事件方法。
- @Extend方法支持参数传递
重复的代码
Image 的 .width(30).height(30) 是重复的
Button的 .fontSize(25).width(150).height(65) .backgroundColor(Color.Green)是重复的
Text 的 .fontSize(20).fontColor(Color.White).fontWeight(500)是重复的
将上面重复的样式代码分别提取到各自定义的@Extend方法中,直接使用@Extend方法
定义格式如下。
@Extend(Image) function consumeImgStyle() {
.width(30)
.height(30)
}
@Extend(Button) function consumeButtonStyle(color: Color) {
.fontSize(25)
.width(150)
.height(65)
.backgroundColor(color)
}
@Extend(Text) function consumeTextStyle(color: Color, size: number, weight: number) {
.fontSize(size)
.fontColor(color)
.fontWeight(weight)
}
将重复样式代码提取之后,直接使用提取后的方法,使用@Extend方法之后代码。
@Entry
@Component
struct customStyle {
@State isOn: boolean = false;
@State isDel: boolean = false;
build() {
Column({ space: 10 }) {
Button({ type: ButtonType.Capsule, stateEffect: true }) {
Row({ space: 10 }) {
Image($r('app.media.icon_new_folder'))
.consumeImgStyle()
Text('新建文件')
.consumeTextStyle(Color.White, 20, 500)
}
}
.consumeButtonStyle(Color.Green)
.onClick(() => {
console.log('我准备开始建立文件夹');
})
Button({ type: ButtonType.Capsule, stateEffect: true }) {
Row({ space: 10 }) {
Image($r('app.media.icon_new_folder'))
.consumeImgStyle()
Text('新建文件')
.consumeTextStyle(Color.White, 20, 500)
}
}
.consumeButtonStyle(Color.Green)
.onClick(() => {
console.log('我准备开始建立文件夹');
})
}
.width('100%')
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
@Extend(Image) function consumeImgStyle() {
.width(30)
.height(30)
}
@Extend(Button) function consumeButtonStyle(color: Color) {
.fontSize(25)
.width(150)
.height(65)
.backgroundColor(color)
}
@Extend(Text) function consumeTextStyle(color: Color, size: number, weight: number) {
.fontSize(size)
.fontColor(color)
.fontWeight(weight)
}
UI结构复用
当页面有多个相同的UI结构时,若每个都单独声明,同样会有大量重复的代码。为避免重复代码,可以将相同的UI结构提炼为一个自定义组件,完成UI结构的复用。
除此之外,ArkTS还提供了一种更轻量的UI结构复用机制@Builder方法,开发者可以将重复使用的UI元素抽象成一个@Builder方法,该方法可在build()方法中调用多次,以完成UI结构的复用。
@Builder装饰的方法同样可用于组件接结构的复用,
- @Builder方法可以定义在组件内或者全局
- @Builder方法定义的是组件内的@Builder方法,可通过this访问当前组件的属性和方法,而全局的@Builder方法则不能
- @Builder方法定义的是组件内的@Builder方法只能用于当前组件,全局的@Builder方法导出(export)后,可用于整个应用。
@Entry
@Component
struct BuilderUI {
@State isOn: boolean = false;
@State isDel: boolean = false;
build() {
Column({ space: 10 }) {
this.builderButton($r('app.media.icon_delete'), '删除文件', () => {
console.log('我准备开始删除文件夹');
})
globalBuilderButton($r('app.media.icon_new_folder'), '新建文件', () => {
console.log('我准备开始建立文件夹');
})
}
.width('100%')
.height("100%")
.justifyContent(FlexAlign.Center)
}
@Builder builderButton(icon: Resource, text: string, callback: () => void) {
Button({ type: ButtonType.Capsule, stateEffect: true }) {
Row({ space: 10 }) {
Image(icon)
.width(30)
.height(30)
Text(text)
.fontSize(20)
.fontColor(Color.White)
.fontWeight(500)
.backgroundColor(Color.Green)
}
}
.fontSize(25)
.width(150)
.height(65)
.onClick(callback)
}
}
@Builder function globalBuilderButton(icon: Resource, text: string, callback: () => void) {
Button({ type: ButtonType.Capsule, stateEffect: true }) {
Row({ space: 10 }) {
Image(icon)
.width(30)
.height(30)
Text(text)
.fontSize(20)
.fontColor(Color.White)
.fontWeight(500)
.backgroundColor(Color.Green)
}
}
.fontSize(25)
.width(150)
.height(65)
.onClick(callback)
}
- @Builder方法支持参数传递规则,分为按值传递和按引用传递。带有花括号的{ } 为引用传递,其余为值传递。
- 按引用传递时,若传递的参数为状态变量,则状态变量的变化将会触发@Builder方法内部UI的刷新,而按值传递时则不会。
@Entry
@Component
struct BuilderUI {
@State status: number = 10;
build() {
Column({ space: 10 }) {
valueText(this.status)
referenceText({status:this.status})
Row({ space: 10 }) {
Button('值传递 - 1')
.consumeButtonStyle()
.onClick(() => {
this.status--
})
Button('引用传递 + 1')
.consumeButtonStyle()
.onClick(() => {
this.status++
})
}
}
.width('100%')
.height("100%")
.justifyContent(FlexAlign.Center)
}
}
@Builder function valueText(count: number) {
Text(`进行值传递: ${count}`).fontSize(30).fontWeight(600)
}
@Builder function referenceText(count: {status:number}) {
Text(`进行引用传递: ${count.status}`).fontSize(30).fontWeight(600)
Text('引用参数传递的是状态变量status,这里内部UI会刷新')
}
@Extend(Button) function consumeButtonStyle() {
.fontSize(20)
.width(140)
.height(65)
}