一、自定义组件
组件是 OpenHarmony 页面最小显示单元,一个页面可由多个组件组合而成,也可只由一个组件组合而成,这些组件可以是ArkUI框架自带系统组件,比如 Text
、 Button
等,也可以是自定义组件,
在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。在进行 UI 界面开发时,通常不是简单的将系统组件进行组合使用,而是需要考虑代码可复用性、业务逻辑与UI分离,后续版本演进等因素。因此,将UI和部分业务逻辑封装成自定义组件是不可或缺的能力。
自定义组件具有以下特点:
- 可组合:允许开发者组合使用系统组件、及其属性和方法。
- 可重用:自定义组件可以被其他组件重用,并作为不同的实例在不同的父组件或容器中使用。
- 数据驱动UI更新:通过状态变量的改变,来驱动UI的刷新。
二、语法如下
自定义一个组件,需要要定义组件名称,做到见名知意,比如定义一个标题栏组件,笔者把它命名为 TitleBar
,为了让系统知道这是一个组件,需要使用 @Component
修饰符和 struct
关键字修饰,格式:【@Component struct + 组件名称】,如下所示:
@Component
struct TitleBar {
build() {
// 省略
}
}
@Entry
@Component struct Index {
build() {
// 省略
}
}
说明如下:
- struct:表示
TitleBar
是一个结构体,使用struct
关键字必须实现build()
方法,否则编译器报错:Require build function for struct
。 - @Component:表示
TitleBar
这个结构体具有组件化的能力,可以成为一个独立的组件。 - @Entry:表示当前组件是页面的总入口,就是页面的根节点,一个页面有且仅有一个
@Entry
修饰符,只有被@Entry
修饰的组件或者子组件才会在页面上显示。
注意:自定义组件禁止添加构造函数,否则编译器报错
三、自定义组件案例
3.1.需求说明
以之前的商品列表展示页面为案例演示:
先给上面的内容添加,标题栏添加返回按钮和刷新按钮,如下:
实现代码如下:
class Item{
//定位属性
name: string
image: any
price: number
constructor(name: string, image: any, price: number) {
this.name = name
this.image = image
this.price = price
}
}
@Entry
@Component
struct ListExample {
private items:Array<Item> = [
new Item("HUAWEI Mate 60 Pro",$r("app.media.mate60"), 7999.00),
new Item("HUAWEI MatePad Pro",$r("app.media.MatePadPro"),4299.00),
new Item("HUAWEI WATCH GT 4", $r("app.media.WATCHGT4"), 1538.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI Mate 60",$r("app.media.mate60"), 5999.00),
new Item("HUAWEI MatePad2 Pro",$r("app.media.MatePadPro"),4599.00),
new Item("HUAWEI WATCH GT 5", $r("app.media.WATCHGT4"), 1638.00),
new Item("HUAWEI FreeBuds Pro 4", $r("app.media.FreeBudsPro3"), 1699.00),
]
build() {
Column({space:8}){
Row(){
//返回按钮
Image($r("app.media.icon_back_button")).width(30).height(30)
Text("商品列表")
.fontSize(30)
.fontWeight(FontWeight.Bold)
Blank()//这里为了有让文字和刷新按钮之间空间,Blank会占满剩余空间
//刷新按钮
Image($r("app.media.icon_refresh_button")).width(30).height(30)
}
.width("100%")
.padding(20)
List({space:10}){
ForEach(this.items,(item: Item)=>{
ListItem(){
Row({space:10}){
Image(item.image).width(100)
Column({space:4}){
Text(item.name).fontSize(15).fontWeight(FontWeight.Bold)
Text(`原价:¥ ${item.price}`).fontColor("#F36").fontSize(18)
}
.height("100%")
.alignItems(HorizontalAlign.Start)
}
.width("90%") //设置宽度
.height(120) //设置高度
.justifyContent(FlexAlign.SpaceBetween) //设置主轴方向主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐。
.backgroundColor("#FFFFFF") //设置背景为白色
.borderRadius(10) //这是圆角班级
.padding(20) //内边距
}
})
}
.alignListItem(ListItemAlign.Center) //ListItem在List交叉轴方向的布局方式,默认为首部对齐。这里改为居中对齐
.height("100%")
.width("100%")
}
.width("100%")
.height("100%")
.backgroundColor("#D3D3D3")
}
}
3.2.页面内部自定义标题组件
上面的代码的将标题部分,抽取出来,形成组件,如下:
//自定义标题组件
@Component
struct TitleBar{
private title:string;
build(){
Row(){
//返回按钮
Image($r("app.media.icon_back_button")).width(30)
//标题
Text(this.title)
.fontSize(30)
.fontWeight(FontWeight.Bold)
Blank()//这里为了有让文字和刷新按钮之间空间,Blank会占满剩余空间
//刷新按钮
Image($r("app.media.icon_refresh_button")).width(30)
}
.width("100%")
.padding(20)
}
}
class Item{
//定位属性
name: string
image: any
price: number
constructor(name: string, image: any, price: number) {
this.name = name
this.image = image
this.price = price
}
}
@Entry
@Component
struct ListExample {
private items:Array<Item> = [
new Item("HUAWEI Mate 60 Pro",$r("app.media.mate60"), 7999.00),
new Item("HUAWEI MatePad Pro",$r("app.media.MatePadPro"),4299.00),
new Item("HUAWEI WATCH GT 4", $r("app.media.WATCHGT4"), 1538.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI Mate 60",$r("app.media.mate60"), 5999.00),
new Item("HUAWEI MatePad2 Pro",$r("app.media.MatePadPro"),4599.00),
new Item("HUAWEI WATCH GT 5", $r("app.media.WATCHGT4"), 1638.00),
new Item("HUAWEI FreeBuds Pro 4", $r("app.media.FreeBudsPro3"), 1699.00),
]
build() {
Column({space:8}){
//调用自定义组件实现标题
TitleBar({title:"商品列表"})
List({space:10}){
ForEach(this.items,(item: Item)=>{
ListItem(){
Row({space:10}){
Image(item.image).width(100)
Column({space:4}){
Text(item.name).fontSize(15).fontWeight(FontWeight.Bold)
Text(`原价:¥ ${item.price}`).fontColor("#F36").fontSize(18)
}
.height("100%")
.alignItems(HorizontalAlign.Start)
}
.width("90%") //设置宽度
.height(120) //设置高度
.justifyContent(FlexAlign.SpaceBetween) //设置主轴方向主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐。
.backgroundColor("#FFFFFF") //设置背景为白色
.borderRadius(10) //这是圆角班级
.padding(20) //内边距
}
})
}
.alignListItem(ListItemAlign.Center) //ListItem在List交叉轴方向的布局方式,默认为首部对齐。这里改为居中对齐
.height("100%")
.width("100%")
}
.width("100%")
.height("100%")
.backgroundColor("#D3D3D3")
}
}
预览效果如下:
上面这样实现没用问题,但是像标题组件这种组件,后续其他模块也要使用,那么就需要定义在外部一个功能的模块,后续调用
3.3.外部自定义标题组件
将上面的标题组件,定位在其他的模块文件中,以供其他的模块调用
1)在ets目录下先创建components目录,然后创建CommonComponents.ets,内容如下:
//自定义标题组件
@Component
export struct TitleBar{
private title:string;
build(){
Row(){
//返回按钮
Image($r("app.media.icon_back_button")).width(30)
//标题
Text(this.title)
.fontSize(30)
.fontWeight(FontWeight.Bold)
Blank()//这里为了有让文字和刷新按钮之间空间,Blank会占满剩余空间
//刷新按钮
Image($r("app.media.icon_refresh_button")).width(30)
}
.width("100%")
.padding(20)
}
}
注意:在struct前面需要添加export,其他模块才可以导入使用
2)删除上一个章节模块中定义的组件,在模块中导入外部定义的组件,代码如下:
//导入组件
import {TitleBar} from "../components/CommonComponents"
class Item{
//定位属性
name: string
image: any
price: number
constructor(name: string, image: any, price: number) {
this.name = name
this.image = image
this.price = price
}
}
@Entry
@Component
struct ListExample {
private items:Array<Item> = [
new Item("HUAWEI Mate 60 Pro",$r("app.media.mate60"), 7999.00),
new Item("HUAWEI MatePad Pro",$r("app.media.MatePadPro"),4299.00),
new Item("HUAWEI WATCH GT 4", $r("app.media.WATCHGT4"), 1538.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI Mate 60",$r("app.media.mate60"), 5999.00),
new Item("HUAWEI MatePad2 Pro",$r("app.media.MatePadPro"),4599.00),
new Item("HUAWEI WATCH GT 5", $r("app.media.WATCHGT4"), 1638.00),
new Item("HUAWEI FreeBuds Pro 4", $r("app.media.FreeBudsPro3"), 1699.00),
]
build() {
Column({space:8}){
//调用自定义组件实现标题
TitleBar({title:"商品列表"})
List({space:10}){
ForEach(this.items,(item: Item)=>{
ListItem(){
Row({space:10}){
Image(item.image).width(100)
Column({space:4}){
Text(item.name).fontSize(15).fontWeight(FontWeight.Bold)
Text(`原价:¥ ${item.price}`).fontColor("#F36").fontSize(18)
}
.height("100%")
.alignItems(HorizontalAlign.Start)
}
.width("90%") //设置宽度
.height(120) //设置高度
.justifyContent(FlexAlign.SpaceBetween) //设置主轴方向主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐。
.backgroundColor("#FFFFFF") //设置背景为白色
.borderRadius(10) //这是圆角班级
.padding(20) //内边距
}
})
}
.alignListItem(ListItemAlign.Center) //ListItem在List交叉轴方向的布局方式,默认为首部对齐。这里改为居中对齐
.height("100%")
.width("100%")
}
.width("100%")
.height("100%")
.backgroundColor("#D3D3D3")
}
}
预览效果如下:
四、自定义函数
上面的自定义组件,可以用于整个项目的一些全局组件的封装调用,但是有时候我们往往需要对某个页面内部的部分内容进行封装调用,这个时候使用自定义函数更加的合适,当然这并不是说不能使用之前的自定义组件来实现
4.1.自定义函数
1)在组件外部自定义函数,这里所说的外部还是在同一个ets文件中,只不过不在struct里面,如下抽取商品列表的Row组件,自定义函数 ProductList ,然后调用,代码如下:
//导入组件
import {TitleBar} from "../components/CommonComponents"
class Item{
//定位属性
name: string
image: any
price: number
constructor(name: string, image: any, price: number) {
this.name = name
this.image = image
this.price = price
}
}
//自定义函数,抽取出商品列表
@Builder function ProductList(item:Item){
Row({space:10}){
Image(item.image).width(100)
Column({space:4}){
Text(item.name).fontSize(15).fontWeight(FontWeight.Bold)
Text(`原价:¥ ${item.price}`).fontColor("#F36").fontSize(18)
}
.height("100%")
.alignItems(HorizontalAlign.Start)
}
.width("90%") //设置宽度
.height(120) //设置高度
.justifyContent(FlexAlign.SpaceBetween) //设置主轴方向主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐。
.backgroundColor("#FFFFFF") //设置背景为白色
.borderRadius(10) //这是圆角班级
.padding(20) //内边距
}
@Entry
@Component
struct ListExample {
private items:Array<Item> = [
new Item("HUAWEI Mate 60 Pro",$r("app.media.mate60"), 7999.00),
new Item("HUAWEI MatePad Pro",$r("app.media.MatePadPro"),4299.00),
new Item("HUAWEI WATCH GT 4", $r("app.media.WATCHGT4"), 1538.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI Mate 60",$r("app.media.mate60"), 5999.00),
new Item("HUAWEI MatePad2 Pro",$r("app.media.MatePadPro"),4599.00),
new Item("HUAWEI WATCH GT 5", $r("app.media.WATCHGT4"), 1638.00),
new Item("HUAWEI FreeBuds Pro 4", $r("app.media.FreeBudsPro3"), 1699.00),
]
build() {
Column({space:8}){
//调用自定义组件实现标题
TitleBar({title:"商品列表"})
List({space:10}){
ForEach(this.items,(item: Item)=>{
ListItem(){
//调用自定义函数
ProductList(item)
}
})
}
.alignListItem(ListItemAlign.Center) //ListItem在List交叉轴方向的布局方式,默认为首部对齐。这里改为居中对齐
.height("100%")
.width("100%")
}
.width("100%")
.height("100%")
.backgroundColor("#D3D3D3")
}
}
注意:
- 在组件外部自定义函数的时候使用@Builder和function关键字,后面写函数名,括号中可以写参数
- 在调用的时候使用 ProductList(item)的形式即可
2)在内部自定义函数,也就是在struct里面,如下抽取商品列表的Row组件(先注释或者删除上面上面在外部定义的函数),在内部自定义函数 ProductList ,然后调用,代码如下:
//导入组件
import {TitleBar} from "../components/CommonComponents"
class Item{
//定位属性
name: string
image: any
price: number
constructor(name: string, image: any, price: number) {
this.name = name
this.image = image
this.price = price
}
}
@Entry
@Component
struct ListExample {
private items:Array<Item> = [
new Item("HUAWEI Mate 60 Pro",$r("app.media.mate60"), 7999.00),
new Item("HUAWEI MatePad Pro",$r("app.media.MatePadPro"),4299.00),
new Item("HUAWEI WATCH GT 4", $r("app.media.WATCHGT4"), 1538.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI Mate 60",$r("app.media.mate60"), 5999.00),
new Item("HUAWEI MatePad2 Pro",$r("app.media.MatePadPro"),4599.00),
new Item("HUAWEI WATCH GT 5", $r("app.media.WATCHGT4"), 1638.00),
new Item("HUAWEI FreeBuds Pro 4", $r("app.media.FreeBudsPro3"), 1699.00),
]
//自定义函数,抽取出商品列表, 内部定义不能加function
@Builder ProductList(item:Item){
Row({space:10}){
Image(item.image).width(100)
Column({space:4}){
Text(item.name).fontSize(15).fontWeight(FontWeight.Bold)
Text(`原价:¥ ${item.price}`).fontColor("#F36").fontSize(18)
}
.height("100%")
.alignItems(HorizontalAlign.Start)
}
.width("90%") //设置宽度
.height(120) //设置高度
.justifyContent(FlexAlign.SpaceBetween) //设置主轴方向主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐。
.backgroundColor("#FFFFFF") //设置背景为白色
.borderRadius(10) //这是圆角班级
.padding(20) //内边距
}
build() {
Column({space:8}){
//调用自定义组件实现标题
TitleBar({title:"商品列表"})
List({space:10}){
ForEach(this.items,(item: Item)=>{
ListItem(){
//调用自定义函数
this.ProductList(item)
}
})
}
.alignListItem(ListItemAlign.Center) //ListItem在List交叉轴方向的布局方式,默认为首部对齐。这里改为居中对齐
.height("100%")
.width("100%")
}
.width("100%")
.height("100%")
.backgroundColor("#D3D3D3")
}
}
注意:
- 在组件内部自定义函数的时候使用@Builder关键字,后面写函数名,括号中可以写参数,注意不能加function关键字,否则会报错
- 在调用的时候使用 this.ProductList(item)的形式即可,this必须要有
4.2.@styles装饰器,仅可封装组件通用属性
1)组件外部定义样式函数,将组件中Column的样式设置,封装成函数 fillStyles,然后调用,如下:
//导入组件
import {TitleBar} from "../components/CommonComponents"
class Item{
//定位属性
name: string
image: any
price: number
constructor(name: string, image: any, price: number) {
this.name = name
this.image = image
this.price = price
}
}
//封装组件通用属性成函数
@Styles function fillStyles(){
.width("100%")
.height("100%")
.backgroundColor("#D3D3D3")
}
@Entry
@Component
struct ListExample {
private items:Array<Item> = [
new Item("HUAWEI Mate 60 Pro",$r("app.media.mate60"), 7999.00),
new Item("HUAWEI MatePad Pro",$r("app.media.MatePadPro"),4299.00),
new Item("HUAWEI WATCH GT 4", $r("app.media.WATCHGT4"), 1538.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI Mate 60",$r("app.media.mate60"), 5999.00),
new Item("HUAWEI MatePad2 Pro",$r("app.media.MatePadPro"),4599.00),
new Item("HUAWEI WATCH GT 5", $r("app.media.WATCHGT4"), 1638.00),
new Item("HUAWEI FreeBuds Pro 4", $r("app.media.FreeBudsPro3"), 1699.00),
]
//自定义函数,抽取出商品列表, 内部定义不能加function
@Builder ProductList(item:Item){
Row({space:10}){
Image(item.image).width(100)
Column({space:4}){
Text(item.name).fontSize(15).fontWeight(FontWeight.Bold)
Text(`原价:¥ ${item.price}`).fontColor("#F36").fontSize(18)
}
.height("100%")
.alignItems(HorizontalAlign.Start)
}
.width("90%") //设置宽度
.height(120) //设置高度
.justifyContent(FlexAlign.SpaceBetween) //设置主轴方向主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐。
.backgroundColor("#FFFFFF") //设置背景为白色
.borderRadius(10) //这是圆角班级
.padding(20) //内边距
}
build() {
Column({space:8}){
//调用自定义组件实现标题
TitleBar({title:"商品列表"})
List({space:10}){
ForEach(this.items,(item: Item)=>{
ListItem(){
//调用自定义函数
this.ProductList(item)
}
})
}
.alignListItem(ListItemAlign.Center) //ListItem在List交叉轴方向的布局方式,默认为首部对齐。这里改为居中对齐
.height("100%")
.width("100%")
}
.fillStyles() //调用外部定义的样式
}
}
注意:
- 在组件外部自定义样式函数的时候使用@Styles和function关键字,后面写函数名,括号中可以写参数
- 在调用的时候使用 .fillStyles() 的形式即可,前面必须有一个点,当成普通的属性使用即可
2)组件内部定义样式函数,将组件中Column的样式设置,封装成函数 fillStyles(先删除之前在外部定义的样式函数),然后调用,如下:
//导入组件
import {TitleBar} from "../components/CommonComponents"
class Item{
//定位属性
name: string
image: any
price: number
constructor(name: string, image: any, price: number) {
this.name = name
this.image = image
this.price = price
}
}
@Entry
@Component
struct ListExample {
private items:Array<Item> = [
new Item("HUAWEI Mate 60 Pro",$r("app.media.mate60"), 7999.00),
new Item("HUAWEI MatePad Pro",$r("app.media.MatePadPro"),4299.00),
new Item("HUAWEI WATCH GT 4", $r("app.media.WATCHGT4"), 1538.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI Mate 60",$r("app.media.mate60"), 5999.00),
new Item("HUAWEI MatePad2 Pro",$r("app.media.MatePadPro"),4599.00),
new Item("HUAWEI WATCH GT 5", $r("app.media.WATCHGT4"), 1638.00),
new Item("HUAWEI FreeBuds Pro 4", $r("app.media.FreeBudsPro3"), 1699.00),
]
//自定义函数,抽取出商品列表, 内部定义不能加function
@Builder ProductList(item:Item){
Row({space:10}){
Image(item.image).width(100)
Column({space:4}){
Text(item.name).fontSize(15).fontWeight(FontWeight.Bold)
Text(`原价:¥ ${item.price}`).fontColor("#F36").fontSize(18)
}
.height("100%")
.alignItems(HorizontalAlign.Start)
}
.width("90%") //设置宽度
.height(120) //设置高度
.justifyContent(FlexAlign.SpaceBetween) //设置主轴方向主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐。
.backgroundColor("#FFFFFF") //设置背景为白色
.borderRadius(10) //这是圆角班级
.padding(20) //内边距
}
//封装组件通用属性成函数,不需要添加function
@Styles fillStyles(){
.width("100%")
.height("100%")
.backgroundColor("#D3D3D3")
}
build() {
Column({space:8}){
//调用自定义组件实现标题
TitleBar({title:"商品列表"})
List({space:10}){
ForEach(this.items,(item: Item)=>{
ListItem(){
//调用自定义函数
this.ProductList(item)
}
})
}
.alignListItem(ListItemAlign.Center) //ListItem在List交叉轴方向的布局方式,默认为首部对齐。这里改为居中对齐
.height("100%")
.width("100%")
}
.fillStyles() //调用外部定义的样式
}
}
注意:
- 在组件内部自定义样式函数的时候使用@Styles关键字,后面写函数名,括号中可以写参数,注意不能加function关键字,否则会报错
- 在调用的时候和上面一样,还是使用 .fillStyles() 的形式即可,前面必须有一个点,当成普通的属性使用即可,不需要添加this
4.3.@Extend装饰器,仅可定义在全局,可以设置组件特有属性
将商品价格Text的样式抽取出来,封装成样式,但是有一个问题,这里的字体样式大小设置,是继承自Text组件,跟上一个章节中宽和高不同,宽和高是公共属性,这时候就无法在使用@styles装饰器, 而是使用@Extend装饰器,但是需要注意@Extend装饰器仅可定义在全局,可以设置组件特有属性,如下:
//导入组件
import {TitleBar} from "../components/CommonComponents"
class Item{
//定位属性
name: string
image: any
price: number
constructor(name: string, image: any, price: number) {
this.name = name
this.image = image
this.price = price
}
}
//@Extend装饰器,仅可定义在全局,可以设置组件特有属性
@Extend(Text) function priceText(){
.fontColor("#F36").fontSize(18)
}
@Entry
@Component
struct ListExample {
private items:Array<Item> = [
new Item("HUAWEI Mate 60 Pro",$r("app.media.mate60"), 7999.00),
new Item("HUAWEI MatePad Pro",$r("app.media.MatePadPro"),4299.00),
new Item("HUAWEI WATCH GT 4", $r("app.media.WATCHGT4"), 1538.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI FreeBuds Pro 3", $r("app.media.FreeBudsPro3"), 1499.00),
new Item("HUAWEI MateBook 14s", $r("app.media.MateBook14s"), 5299.00),
new Item("HUAWEI Mate 60",$r("app.media.mate60"), 5999.00),
new Item("HUAWEI MatePad2 Pro",$r("app.media.MatePadPro"),4599.00),
new Item("HUAWEI WATCH GT 5", $r("app.media.WATCHGT4"), 1638.00),
new Item("HUAWEI FreeBuds Pro 4", $r("app.media.FreeBudsPro3"), 1699.00),
]
//自定义函数,抽取出商品列表, 内部定义不能加function
@Builder ProductList(item:Item){
Row({space:10}){
Image(item.image).width(100)
Column({space:4}){
Text(item.name).fontSize(15).fontWeight(FontWeight.Bold)
Text(`原价:¥ ${item.price}`)
.priceText() //使用自定义的样式
}
.height("100%")
.alignItems(HorizontalAlign.Start)
}
.width("90%") //设置宽度
.height(120) //设置高度
.justifyContent(FlexAlign.SpaceBetween) //设置主轴方向主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐。
.backgroundColor("#FFFFFF") //设置背景为白色
.borderRadius(10) //这是圆角班级
.padding(20) //内边距
}
//封装组件通用属性成函数,不需要添加function
@Styles fillStyles(){
.width("100%")
.height("100%")
.backgroundColor("#D3D3D3")
}
build() {
Column({space:8}){
//调用自定义组件实现标题
TitleBar({title:"商品列表"})
List({space:10}){
ForEach(this.items,(item: Item)=>{
ListItem(){
//调用自定义函数
this.ProductList(item)
}
})
}
.alignListItem(ListItemAlign.Center) //ListItem在List交叉轴方向的布局方式,默认为首部对齐。这里改为居中对齐
.height("100%")
.width("100%")
}
.fillStyles() //调用外部定义的样式
}
}
注意:
- 在组件内部自定义样式函数的时候使用@Extend和function关键字,后面写函数名,括号中可以写参数
- 在调用的时候和上面一样,还是使用 .priceText() 的形式即可,前面必须有一个点,当成普通的属性使用即可,不需要添加this
- 尽可以定义在全局使用,不可以在内部定义