赞
踩
以 【HarmonyOS】ArkUI - 列表布局(List) 那一篇文章的2024春节档电影新片票房榜
列表例子为例:
@Entry @Component struct Index { ... build() { Column({ space: 8 }) { // 标题部分 Row() { ... } // 电影列表部分 List() { ForEach( ... ) } } } }
这是整体的代码结构,省略了细节部分。整个页面是一个从上到下的列式布局,所以我们使用了 Column 容器。然后页面分成了两部分,第一部分是顶部的标题,第二部分是电影列表,由于每一行的内容基本相似,所以我们使用 ForEach 在内部循环渲染电影对应的卡片。
以上面的标题部分为例,我们知道标题部分其实是一个标准化的功能,也就是说不仅这个页面需要这样的标题,其他页面也需要。比如产品在设计UE时,通常来说会把列表页面和列表详情页的标题部分设置成相似的。如果在每个页面里都写类似的标题代码,复用性会很差,所以为了解决这个问题我们可以把标题部分封装到自定义组件里。
@Component
struct Header {
build() {
// 标题部分
Row() {
...
}
}
}
我们定义了一个结构体 Header
,代表页面的头部。然后加上 @Component
装饰器,这样一个组件就声明出来了。紧接着,可以把标题部分的代码抽取到 builde() { }
里,这样一个可复用的标题的功能就封装好了。
将来在电影列表页面里,我需要写标题,不需要在重新写标题代码了,直接引用这个 Header 组件就行了:
@Entry @Component struct Index { ... build() { Column({ space: 8 }) { // 标题部分 Header() // 电影列表部分 List() { ForEach( ... ) } } } }
定义在页面内部的自定义组件完整代码如下:
@Component struct Header { private title: string build() { Row() { Text(this.title) .fontSize(30) .fontWeight(FontWeight.Bold) } } } @Entry @Component struct Index { ... build() { Column({ space: 8 }) { // 标题部分 Header({ title: '2024春节档新片票房榜' }) .margin({ bottom: 20 }) ... } } }
但是,如果定义在页面内部,也就意味着只有在这个页面能用,换一个页面就用不了了。所以最佳的方案时定义在单独的文件里。
在 entry 的 ets 文件夹里新建 components 文件夹,并在里面新建一个 CommonComponents.ets 文件。将上面 Header 代码拷贝到这个文件里,为了能让别的文件使用这段代码,需要做一些修改:
@Component
export struct Header {
build() {
Row() {
...
}
}
}
使用 export
将 Header 导出,这样别的文件才能 import
导入使用:
import { Header } from '../components/CommonComponents'
定义在页面外部的自定义组件完整代码如下:
CommonComponents.ets
@Component
export struct Header {
private title: string
build() {
Row() {
Text(this.title)
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
}
}
Index.ets
import { Header } from '../components/CommonComponents' @Entry @Component struct Index { ... build() { Column({ space: 8 }) { // 标题部分 Header({ title: '2024春节档新片票房榜' }) .margin({ bottom: 20 }) ... } } }
@Builder
这是我们的 Index.ets 代码:
... @Entry @Component struct Index { ... build() { Column({ space: 8 }) { ... // 电影列表部分 List({ space: 8 }) { ForEach( this.items, (item: Item) => { ListItem() { Row({ space: 8 }) { Image(item.image) .width(157) .height(220) Column() { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text(item.box_office) .fontSize(18) } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .height(220) } } ) } .width('100%') .height('100%') } .width('100%') .height('100%') .padding(8) } }
从这段代码可以发现,List 里面的代码可读性不高。最好是能把下面这段代码封装起来:
Row({ space: 8 }) { Image(item.image) .width(157) .height(220) Column() { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text(item.box_office) .fontSize(18) } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .height(220)
可以使用自定义组件,也可以使用自定构建函数 @Builder
,它用来做这种内部的页面封装会更加合适一些。
自定构建函数顾名思义就是用来构建页面的一个函数,可以把相关代码封装进去:
全局自定义构建函数
代码结构:
@Builder function 函数名() {
...
}
完整代码:
... @Builder function ItemCard(item:Item) { Row({ space: 8 }) { Image(item.image) .width(157) .height(220) Column() { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text(item.box_office) .fontSize(18) } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .height(220) } @Entry @Component struct Index { ... build() { Column({ space: 8 }) { ... // 电影列表部分 List({ space: 8 }) { ForEach( this.items, (item: Item) => { ListItem() { ItemCard(item) } } ) } .width('100%') .height('100%') } .width('100%') .height('100%') .padding(8) } }
组件内自定义构建函数
代码结构:
@Builder 函数名() {
...
}
完整代码:
... @Entry @Component struct Index { ... build() { Column({ space: 8 }) { ... // 电影列表部分 List({ space: 8 }) { ForEach( this.items, (item: Item) => { ListItem() { this.ItemCard(item) } } ) } .width('100%') .height('100%') } .width('100%') .height('100%') .padding(8) } @Builder ItemCard(item: Item) { Row({ space: 8 }) { Image(item.image) .width(157) .height(220) Column() { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text(item.box_office) .fontSize(18) } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .height(220) } }
@Styles
@Entry @Component struct Index { ... build() { Column() { ... } .width('100%') .height('100%') .padding(8) } ... }
如上代码所示,是一个 Column 容器,这个 Column 是有很多样式的,比如这里的宽100%、高100%等,这种样式可以认为是 App 的统一样式,也就是通用样式,如果每个页面都去写这些代码是不是也是浪费,这种也可以做抽取,这是对样式的抽取,就要用到 @Styles
装饰器。
全局公共样式
代码结构:
@Styles function 函数名() {
...
}
完整代码:
@Styles function fillScreen() { .width('100%') .height('100%') .padding(8) } @Entry @Component struct Index { ... build() { Column() { ... } .fillScreen() } ... }
内部共样式
代码结构:
@Styles 函数名() {
...
}
完整代码:
@Entry @Component struct Index { @Styles function fillScreen() { .width('100%') .height('100%') .padding(8) } ... build() { Column() { ... } .fillScreen() } ... }
@Extend
Text(item.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
如上代码所示,fontSize 和 fontWeight 是 Text 组件的特有属性,如果页面中有相同的代码,可以使用 @Extend
抽取。
代码结构:
@Extend(组件) function 函数名() {
...
}
完整代码:
@Extend(Text) function nameText() {
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
Text(item.name)
.nameText()
切记 @Extend
不能写在组件内,只能写在全局。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。