赞
踩
传统开发,结构,样式,行为
TypeScript语法去查看我的其他文章
创建工程选着模板
对文件详细介绍
接下来,我们来根据下面的效果来,学习Image,Text,TextInput,Button,Slider组件
安装模拟器
https://b11et3un53m.feishu.cn/wiki/LGprwXi1biC7TQkWPNDc45IXndh
到官网查找权限使用方式
官方文档访问控制:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/2_1_u8bbf_u95ee_u63a7_u5236-0000001544583929-V2
添加权限
使用网络图片
@Entry @Component struct Index { @State message: string = 'Hello World' build() { Row() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) .fontColor('#36D') .onClick(() => { this.message = 'Hello ArkTS!' }) Image('https://img2.baidu.com/it/u=2690715796,3320143179&fm=253&fmt=auto&app=138&f=JPEG?w=749&h=500') .width(250) } .width('100%') } .height('100%') } }
Image($r('app.media.icon'))
.width(250)
Image($r('app.media.icon'))
.width(250)
.interpolation(ImageInterpolation.High) // 抗锯齿(不用记忆直接找文档,提示也有)
下图这种方式,直接写死
我们可以根据语言环境动态显示文本,到底是中文还是英文,要先写提示词
文件读取顺序先到,限定词目录里读取,找不到再到base里读取
所以要在限定词目录里写数据还要再base里写数据(一份数据写三次)
在限定次目录里,写提示词
在base里写提示词
上面这种方式在在,三个不同的json文件里配置,太麻烦,我们有办法,一下都配置好(下面讲)
动态显示文本
切换环境
@Entry @Component struct Index { @State imageWidth: number = 150 build(){ Column(){ // 类似Bootstrap的栅格系统,使用行列布局(后面会细讲,或者看官方文档) Row(){ Image($r('app.media.icon')) .width(this.imageWidth) .interpolation(ImageInterpolation.High) // 抗锯齿 }.width('100%') .height(400) .justifyContent(FlexAlign.Center) Row(){ Text($r('app.string.width_label')) .fontSize(20) .fontWeight(FontWeight.Bold) TextInput({text: this.imageWidth.toFixed(0)}) .width(150) .backgroundColor('#36D') .type(InputType.Number) // 限制文本输入框必须是数字 .onChange( value => { this.imageWidth = parseInt(value) // 注意:这里value这个参数是,当你输入的时候,就会拿到输入的内容,只不过是字符串类型,需要转成数字 }) } .width('100%') .padding({left: 14, right: 14}) .justifyContent(FlexAlign.SpaceBetween) // 类似css里的flax布局 } } }
@Entry @Component struct Index { @State imageWidth: number = 150 build(){ Column(){ // 类似Bootstrap的栅格系统,使用行列布局(后面会细讲,或者看官方文档) Row(){ Image($r('app.media.icon')) .width(this.imageWidth) .interpolation(ImageInterpolation.High) // 抗锯齿 }.width('100%') .height(400) .justifyContent(FlexAlign.Center) Row(){ Text($r('app.string.width_label')) .fontSize(20) .fontWeight(FontWeight.Bold) TextInput({text: this.imageWidth.toFixed(0)}) .width(150) .backgroundColor('#36D') .type(InputType.Number) // 限制文本输入框必须是数字 .onChange( value => { this.imageWidth = parseInt(value) // 注意:这里value这个参数是,当你输入的时候,就会拿到输入的内容,只不过是字符串类型,需要转成数字 }) } .width('100%') .padding({left: 14, right: 14}) .justifyContent(FlexAlign.SpaceBetween) // 类似css里的flax布局 Button('缩小') .width(80) .fontSize(20) .onClick(() =>{ if(this.imageWidth >= 10){ this.imageWidth -= 10 } }) Button('放大') .width(80) .fontSize(20) .onClick(() =>{ if(this.imageWidth < 300){ this.imageWidth += 10 } }) } } }
@Entry @Component struct Index { @State imageWidth: number = 150 build(){ Column(){ // 类似Bootstrap的栅格系统,使用行列布局(后面会细讲,或者看官方文档) Row(){ Image($r('app.media.icon')) .width(this.imageWidth) .interpolation(ImageInterpolation.High) // 抗锯齿 }.width('100%') .height(400) .justifyContent(FlexAlign.Center) Row(){ Text($r('app.string.width_label')) .fontSize(20) .fontWeight(FontWeight.Bold) TextInput({text: this.imageWidth.toFixed(0)}) .width(150) .backgroundColor('#36D') .type(InputType.Number) // 限制文本输入框必须是数字 .onChange( value => { this.imageWidth = parseInt(value) // 注意:这里value这个参数是,当你输入的时候,就会拿到输入的内容,只不过是字符串类型,需要转成数字 }) } .width('100%') .padding({left: 14, right: 14}) .justifyContent(FlexAlign.SpaceBetween) // 类似css里的flax布局 Button('缩小') .width(80) .fontSize(20) .onClick(() =>{ if(this.imageWidth >= 10){ this.imageWidth -= 10 } }) Button('放大') .width(80) .fontSize(20) .onClick(() =>{ if(this.imageWidth < 300){ this.imageWidth += 10 } }) Slider({ min:100, max: 300, value: this.imageWidth, step:10 }) .width('100%') .blockColor('#36D') .trackThickness(5) // 滑条粗细 .showTips(true) .onChange( value => { this.imageWidth = value }) } } }
交叉轴默认center
@Entry @Component struct Index { @State imageWidth: number = 150 build(){ Column(){ // 类似Bootstrap的栅格系统,使用行列布局(后面会细讲,或者看官方文档) Row(){ Image($r('app.media.icon')) .width(this.imageWidth) .interpolation(ImageInterpolation.High) // 抗锯齿 }.width('100%') .height(400) .justifyContent(FlexAlign.Center) Row(){ Text($r('app.string.width_label')) .fontSize(20) .fontWeight(FontWeight.Bold) TextInput({text: this.imageWidth.toFixed(0)}) .width(150) .fontWeight(FontWeight.Bold) .backgroundColor('#36D') .type(InputType.Number) // 限制文本输入框必须是数字 .onChange( value => { this.imageWidth = parseInt(value) // 注意:这里value这个参数是,当你输入的时候,就会拿到输入的内容,只不过是字符串类型,需要转成数字 }) } .width('100%') .padding({left: 14, right: 14}) .justifyContent(FlexAlign.SpaceBetween) // 类似css里的flax布局 Divider() .width('91%') Row(){ Button('缩小') .width(80) .fontSize(20) .onClick(() =>{ if(this.imageWidth >= 10){ this.imageWidth -= 10 } }) Button('放大') .width(80) .fontSize(20) .onClick(() =>{ if(this.imageWidth < 300){ this.imageWidth += 10 } }) } .width('100%') .margin({top: 35, bottom: 35}) .justifyContent(FlexAlign.SpaceEvenly) Slider({ min:100, max: 300, value: this.imageWidth, step:10 }) .width('100%') .blockColor('#36D') .trackThickness(5) // 滑条粗细 .showTips(true) .onChange( value => { this.imageWidth = value }) } .width('100%') .height('100%') } }
准备基础样式结构
class Item { name: string image: ResourceStr price: number discount: number constructor(name: string, image: ResourceStr, price: number, discount: number = 0) { this.name = name this.image = image this.price = price this.discount = discount } } @Entry @Component struct ItemPage { // 商品数据 private items: Array<Item> = [ new Item('华为Mate60', $r('app.media.mate60'), 6999, 500), new Item('MateBookProX', $r('app.media.mateBookProX'), 13999), new Item('WatchGT4', $r('app.media.watchGT4'), 1438), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999) ] build() { Column({ space: 8 }) { Row() { Text('商品列表') .fontSize(30) .fontWeight(FontWeight.Bold) } .width('100%') .height(30) .margin({ bottom: 20 }) // Row({space: 10}){ Image($r('app.media.mate60')) .width(100) Column({space: 4}){ Text('华为Mate60') .fontSize(20) .fontWeight(FontWeight.Bold) Text('¥6999') .fontColor('#CCC') .fontSize(14) .decoration({type: TextDecorationType.LineThrough}) Text('折扣价:¥ 5999') .fontColor('#F36') .fontSize(18) Text('补贴:¥ 1000' ) .fontColor('#F36') .fontSize(18) } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .backgroundColor('#FFF') .borderRadius(20) .height(120) .padding(20) } .width('100%') .height('100%') .backgroundColor('#EFEFEF') } }
开始使用循环渲染
就是之前写的卡片这一行放到ForEach里来
class Item { name: string image: ResourceStr price: number discount: number constructor(name: string, image: ResourceStr, price: number, discount: number = 0) { this.name = name this.image = image this.price = price this.discount = discount } } @Entry @Component struct ItemPage { // 商品数据 private items: Array<Item> = [ new Item('华为Mate60', $r('app.media.mate60'), 6999, 500), new Item('MateBookProX', $r('app.media.mateBookProX'), 13999), new Item('WatchGT4', $r('app.media.watchGT4'), 1438), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999) ] build() { Column({ space: 8 }) { Row() { Text('商品列表') .fontSize(30) .fontWeight(FontWeight.Bold) } .width('100%') .height(30) .margin({ bottom: 20 }) // ForEach( this.items, (item: Item) => { Row({space: 10}){ Image(item.image) .width(100) Column({space: 4}){ Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('¥6999') .fontColor('#CCC') .fontSize(14) .decoration({type: TextDecorationType.LineThrough}) Text('折扣价:¥ 5999') .fontColor('#F36') .fontSize(18) Text('补贴:¥ 1000' ) .fontColor('#F36') .fontSize(18) } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .backgroundColor('#FFF') .borderRadius(20) .height(120) .padding(20) } ) } .width('100%') .height('100%') .backgroundColor('#EFEFEF') } }
ForEach就会了
根据条件展示不同内容
class Item { name: string image: ResourceStr price: number discount: number constructor(name: string, image: ResourceStr, price: number, discount: number = 0) { this.name = name this.image = image this.price = price this.discount = discount } } @Entry @Component struct ItemPage { // 商品数据 private items: Array<Item> = [ new Item('华为Mate60', $r('app.media.mate60'), 6999, 500), new Item('MateBookProX', $r('app.media.mateBookProX'), 13999), new Item('WatchGT4', $r('app.media.watchGT4'), 1438), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999) ] build() { Column({ space: 8 }) { Row() { Text('商品列表') .fontSize(30) .fontWeight(FontWeight.Bold) } .width('100%') .height(30) .margin({ bottom: 20 }) // ForEach( this.items, (item: Item) => { Row({space: 10}){ Image(item.image) .width(100) Column({space: 4}){ if(item.discount){ Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('原价:¥'+ item.price) .fontColor('#CCC') .fontSize(14) .decoration({type: TextDecorationType.LineThrough}) Text('折扣价:¥' + item.discount) .fontColor('#F36') .fontSize(18) Text('补贴:¥ ' + (item.price - item.discount) ) .fontColor('#F36') .fontSize(18) }else { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('¥'+ item.price) .fontColor('#F36') .fontSize(18) } } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .backgroundColor('#FFF') .borderRadius(20) .height(120) .padding(20) } ) } .width('100%') .height('100%') .backgroundColor('#EFEFEF') } }
使用List组件
class Item { name: string image: ResourceStr price: number discount: number constructor(name: string, image: ResourceStr, price: number, discount: number = 0) { this.name = name this.image = image this.price = price this.discount = discount } } @Entry @Component struct ItemPage { // 商品数据 private items: Array<Item> = [ new Item('华为Mate60', $r('app.media.mate60'), 6999, 500), new Item('MateBookProX', $r('app.media.mateBookProX'), 13999), new Item('WatchGT4', $r('app.media.watchGT4'), 1438), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999) ] build() { Column({ space: 8 }) { Row() { Text('商品列表') .fontSize(30) .fontWeight(FontWeight.Bold) } .width('100%') .height(30) .margin({ bottom: 20 }) // List({space: 8}) { ForEach( this.items, (item: Item) => { ListItem(){ Row({space: 10}){ Image(item.image) .width(100) Column({space: 4}){ if(item.discount){ Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('原价:¥'+ item.price) .fontColor('#CCC') .fontSize(14) .decoration({type: TextDecorationType.LineThrough}) Text('折扣价:¥' + item.discount) .fontColor('#F36') .fontSize(18) Text('补贴:¥ ' + (item.price - item.discount) ) .fontColor('#F36') .fontSize(18) }else { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('¥'+ item.price) .fontColor('#F36') .fontSize(18) } } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .backgroundColor('#FFF') .borderRadius(20) .height(120) .padding(20) } } ) } } .width('100%') .height('100%') .backgroundColor('#EFEFEF') } }
// 标题部分
Row() {
Image($r('app.media.ic_public_back'))
.width(30)
Text('商品列表')
.fontSize(30)
.fontWeight(FontWeight.Bold)
Blank()
Image($r('app.media.ic_public_refresh'))
.width(30)
}
.width('100%')
.height(30)
.margin({ bottom: 20 })
//
import resourceManager from '@ohos.resourceManager' class Item { name: string image: ResourceStr price: number discount: number constructor(name: string, image: ResourceStr, price: number, discount: number = 0) { this.name = name this.image = image this.price = price this.discount = discount } } @Component struct Header{ private title: ResourceStr build(){ // 标题部分 Row() { Image($r('app.media.ic_public_back')) .width(30) Text(this.title) .fontSize(30) .fontWeight(FontWeight.Bold) Blank() Image($r('app.media.ic_public_refresh')) .width(30) } .width('100%') .height(30) // .margin({ bottom: 20 }) // 和外界的距离,使用组件的人自己去管 } } @Entry @Component struct ItemPage { // 商品数据 private items: Array<Item> = [ new Item('华为Mate60', $r('app.media.mate60'), 6999, 500), new Item('MateBookProX', $r('app.media.mateBookProX'), 13999), new Item('WatchGT4', $r('app.media.watchGT4'), 1438), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999) ] build() { Column({ space: 8 }) { // 标题部分 Header({title: '商品列表'}) .margin({ bottom: 20 }) // 自定义组件是可以加样式的 // 商品部分 List({space: 8}) { ForEach( this.items, (item: Item) => { ListItem(){ Row({space: 10}){ Image(item.image) .width(100) Column({space: 4}){ if(item.discount){ Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('原价:¥'+ item.price) .fontColor('#CCC') .fontSize(14) .decoration({type: TextDecorationType.LineThrough}) Text('折扣价:¥' + item.discount) .fontColor('#F36') .fontSize(18) Text('补贴:¥ ' + (item.price - item.discount) ) .fontColor('#F36') .fontSize(18) }else { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('¥'+ item.price) .fontColor('#F36') .fontSize(18) } } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .backgroundColor('#FFF') .borderRadius(20) .height(120) .padding(20) } } ) } } .width('100%') .height('100%') .backgroundColor('#EFEFEF') .padding(20) } }
创建目录及文件
导出
// src/main/ets/common/components/CommonComponents.ets @Component export struct Header{ private title: ResourceStr build(){ // 标题部分 Row() { Image($r('app.media.ic_public_back')) .width(30) Text(this.title) .fontSize(30) .fontWeight(FontWeight.Bold) Blank() Image($r('app.media.ic_public_refresh')) .width(30) } .width('100%') .height(30) // .margin({ bottom: 20 }) // 和外界的距离,使用组件的人自己去管 } }
引用
import resourceManager from '@ohos.resourceManager' class Item { name: string image: ResourceStr price: number discount: number constructor(name: string, image: ResourceStr, price: number, discount: number = 0) { this.name = name this.image = image this.price = price this.discount = discount } } /* @Component struct Header{ private title: ResourceStr build(){ // 标题部分 Row() { Image($r('app.media.ic_public_back')) .width(30) Text(this.title) .fontSize(30) .fontWeight(FontWeight.Bold) Blank() Image($r('app.media.ic_public_refresh')) .width(30) } .width('100%') .height(30) // .margin({ bottom: 20 }) // 和外界的距离,使用组件的人自己去管 } }*/ import {Header} from '../common/components/CommonComponents' @Entry @Component struct ItemPage { // 商品数据 private items: Array<Item> = [ new Item('华为Mate60', $r('app.media.mate60'), 6999, 500), new Item('MateBookProX', $r('app.media.mateBookProX'), 13999), new Item('WatchGT4', $r('app.media.watchGT4'), 1438), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999) ] build() { Column({ space: 8 }) { // 标题部分 Header({title: '商品列表'}) .margin({ bottom: 20 }) // 自定义组件是可以加样式的 // 商品部分 List({space: 8}) { ForEach( this.items, (item: Item) => { ListItem(){ Row({space: 10}){ Image(item.image) .width(100) Column({space: 4}){ if(item.discount){ Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('原价:¥'+ item.price) .fontColor('#CCC') .fontSize(14) .decoration({type: TextDecorationType.LineThrough}) Text('折扣价:¥' + item.discount) .fontColor('#F36') .fontSize(18) Text('补贴:¥ ' + (item.price - item.discount) ) .fontColor('#F36') .fontSize(18) }else { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('¥'+ item.price) .fontColor('#F36') .fontSize(18) } } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .backgroundColor('#FFF') .borderRadius(20) .height(120) .padding(20) } } ) } } .width('100%') .height('100%') .backgroundColor('#EFEFEF') .padding(20) } }
由于我们的代码可读性差,我们将卡片封装成组件
import resourceManager from '@ohos.resourceManager' class Item { name: string image: ResourceStr price: number discount: number constructor(name: string, image: ResourceStr, price: number, discount: number = 0) { this.name = name this.image = image this.price = price this.discount = discount } } /* @Component struct Header{ private title: ResourceStr build(){ // 标题部分 Row() { Image($r('app.media.ic_public_back')) .width(30) Text(this.title) .fontSize(30) .fontWeight(FontWeight.Bold) Blank() Image($r('app.media.ic_public_refresh')) .width(30) } .width('100%') .height(30) // .margin({ bottom: 20 }) // 和外界的距离,使用组件的人自己去管 } }*/ import {Header} from '../common/components/CommonComponents' // 全局自定义构建函数 @Builder function ItemCard(item: Item) { Row({space: 10}){ Image(item.image) .width(100) Column({space: 4}){ if(item.discount){ Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('原价:¥'+ item.price) .fontColor('#CCC') .fontSize(14) .decoration({type: TextDecorationType.LineThrough}) Text('折扣价:¥' + item.discount) .fontColor('#F36') .fontSize(18) Text('补贴:¥ ' + (item.price - item.discount) ) .fontColor('#F36') .fontSize(18) }else { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('¥'+ item.price) .fontColor('#F36') .fontSize(18) } } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .backgroundColor('#FFF') .borderRadius(20) .height(120) .padding(20) } @Entry @Component struct ItemPage { // 商品数据 private items: Array<Item> = [ new Item('华为Mate60', $r('app.media.mate60'), 6999, 500), new Item('MateBookProX', $r('app.media.mateBookProX'), 13999), new Item('WatchGT4', $r('app.media.watchGT4'), 1438), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999) ] build() { Column({ space: 8 }) { // 标题部分 Header({title: '商品列表'}) .margin({ bottom: 20 }) // 自定义组件是可以加样式的 // 商品部分 List({space: 8}) { ForEach( this.items, (item: Item) => { ListItem(){ ItemCard(item) } } ) } } .width('100%') .height('100%') .backgroundColor('#EFEFEF') .padding(20) } }
局部的,只有组件自己能用,别人用不了
import resourceManager from '@ohos.resourceManager' class Item { name: string image: ResourceStr price: number discount: number constructor(name: string, image: ResourceStr, price: number, discount: number = 0) { this.name = name this.image = image this.price = price this.discount = discount } } /* @Component struct Header{ private title: ResourceStr build(){ // 标题部分 Row() { Image($r('app.media.ic_public_back')) .width(30) Text(this.title) .fontSize(30) .fontWeight(FontWeight.Bold) Blank() Image($r('app.media.ic_public_refresh')) .width(30) } .width('100%') .height(30) // .margin({ bottom: 20 }) // 和外界的距离,使用组件的人自己去管 } }*/ import {Header} from '../common/components/CommonComponents' // // 全局自定义构建函数 // @Builder function ItemCard(item: Item) { // Row({space: 10}){ // Image(item.image) // .width(100) // Column({space: 4}){ // if(item.discount){ // Text(item.name) // .fontSize(20) // .fontWeight(FontWeight.Bold) // Text('原价:¥'+ item.price) // .fontColor('#CCC') // .fontSize(14) // .decoration({type: TextDecorationType.LineThrough}) // Text('折扣价:¥' + item.discount) // .fontColor('#F36') // .fontSize(18) // Text('补贴:¥ ' + (item.price - item.discount) ) // .fontColor('#F36') // .fontSize(18) // }else { // Text(item.name) // .fontSize(20) // .fontWeight(FontWeight.Bold) // Text('¥'+ item.price) // .fontColor('#F36') // .fontSize(18) // // } // // } // .height('100%') // .alignItems(HorizontalAlign.Start) // } // .width('100%') // .backgroundColor('#FFF') // .borderRadius(20) // .height(120) // .padding(20) // } @Entry @Component struct ItemPage { // 商品数据 private items: Array<Item> = [ new Item('华为Mate60', $r('app.media.mate60'), 6999, 500), new Item('MateBookProX', $r('app.media.mateBookProX'), 13999), new Item('WatchGT4', $r('app.media.watchGT4'), 1438), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999) ] build() { Column({ space: 8 }) { // 标题部分 Header({title: '商品列表'}) .margin({ bottom: 20 }) // 自定义组件是可以加样式的 // 商品部分 List({space: 8}) { ForEach( this.items, (item: Item) => { ListItem(){ this.ItemCard(item) } } ) } } .width('100%') .height('100%') .backgroundColor('#EFEFEF') .padding(20) } // 局部自定义构建函数 @Builder ItemCard(item: Item) { Row({space: 10}){ Image(item.image) .width(100) Column({space: 4}){ if(item.discount){ Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('原价:¥'+ item.price) .fontColor('#CCC') .fontSize(14) .decoration({type: TextDecorationType.LineThrough}) Text('折扣价:¥' + item.discount) .fontColor('#F36') .fontSize(18) Text('补贴:¥ ' + (item.price - item.discount) ) .fontColor('#F36') .fontSize(18) }else { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('¥'+ item.price) .fontColor('#F36') .fontSize(18) } } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .backgroundColor('#FFF') .borderRadius(20) .height(120) .padding(20) } }
鸿蒙系统中,自定义组件和自定义构建函数都是用于增强用户界面开发灵活性和可复用性的机制,但它们在用途、使用场景和功能特性上存在一些根本的区别:
自定义组件 (Custom Component)
功能定位:自定义组件是对基本UI组件的扩展或组合,用于封装特定的UI布局或交互逻辑。它允许开发者创建可复用的、具有独立功能和生命周期管理的UI模块。
结构与复杂性:自定义组件可以包含多个子组件、布局、样式以及自己的状态管理和生命周期方法(如onCreate, onDraw, onUpdate等)。这使得它们能够处理更复杂的UI需求和交互逻辑。
复用性:设计良好的自定义组件可以跨多个页面或应用重复使用,提高代码的模块化和维护性。
成员属性与方法:自定义组件可以定义自己的属性(成员变量)、方法(包括构造函数、初始化方法等),并支持数据绑定和事件监听。
自定义构建函数 (@Builder)
功能定位:自定义构建函数是一种轻量级的UI构建辅助工具,它作为组件内部的一部分,用于简化组件内部的构建逻辑。通过装饰器@Builder标记,这些函数可以在组件的build方法中被调用以生成特定UI部分。
使用范围:自定义构建函数通常限制在定义它们的组件内部使用,不允许外部直接调用。这意味着它们主要用于组件内部的逻辑组织和代码复用,而非跨组件共享。
目的:主要目的是为了提升代码的可读性和可维护性,通过将复杂的UI构建过程分解为小的、易于管理的函数,使得组件的build方法更加清晰。
局限性:相比自定义组件,自定义构建函数不涉及组件的生命周期管理,也不具备组件的完全独立性,它们依赖于宿主组件的上下文环境。
总结
自定义组件关注于创建可复用的UI模块,拥有完整的生命周期和独立的功能,适合构建复杂的、可跨项目共享的界面元素。而自定义构建函数则专注于优化单个组件内部的构建流程,提高代码结构的清晰度,但不具备组件的完整特性和独立性。两者结合使用,可以有效提升鸿蒙应用的开发效率和代码质量。
@Styles function fillScreen(){
.width('100%')
.height('100%')
.backgroundColor('#EFEFEF')
.padding(20)
}
// 局部位公共样式函数
@Styles fillScreen(){
.width('100%')
.height('100%')
.backgroundColor('#EFEFEF')
.padding(20)
}
这样就可以解决,非公共些样式的封装
@Extend(Text) function priceText(){
.fontColor('#F36')
.fontSize(18)
}
全部代码
import resourceManager from '@ohos.resourceManager' class Item { name: string image: ResourceStr price: number discount: number constructor(name: string, image: ResourceStr, price: number, discount: number = 0) { this.name = name this.image = image this.price = price this.discount = discount } } /* @Component struct Header{ private title: ResourceStr build(){ // 标题部分 Row() { Image($r('app.media.ic_public_back')) .width(30) Text(this.title) .fontSize(30) .fontWeight(FontWeight.Bold) Blank() Image($r('app.media.ic_public_refresh')) .width(30) } .width('100%') .height(30) // .margin({ bottom: 20 }) // 和外界的距离,使用组件的人自己去管 } }*/ import {Header} from '../common/components/CommonComponents' // // 全局自定义构建函数 // @Builder function ItemCard(item: Item) { // Row({space: 10}){ // Image(item.image) // .width(100) // Column({space: 4}){ // if(item.discount){ // Text(item.name) // .fontSize(20) // .fontWeight(FontWeight.Bold) // Text('原价:¥'+ item.price) // .fontColor('#CCC') // .fontSize(14) // .decoration({type: TextDecorationType.LineThrough}) // Text('折扣价:¥' + item.discount) // .fontColor('#F36') // .fontSize(18) // Text('补贴:¥ ' + (item.price - item.discount) ) // .fontColor('#F36') // .fontSize(18) // }else { // Text(item.name) // .fontSize(20) // .fontWeight(FontWeight.Bold) // Text('¥'+ item.price) // .fontColor('#F36') // .fontSize(18) // // } // // } // .height('100%') // .alignItems(HorizontalAlign.Start) // } // .width('100%') // .backgroundColor('#FFF') // .borderRadius(20) // .height(120) // .padding(20) // } // 全局公共样式函数 // @Styles function fillScreen(){ // .width('100%') // .height('100%') // .backgroundColor('#EFEFEF') // .padding(20) // } // 继承模式,只能写在全局 @Extend(Text) function priceText(){ .fontColor('#F36') .fontSize(18) } @Entry @Component struct ItemPage { // 商品数据 private items: Array<Item> = [ new Item('华为Mate60', $r('app.media.mate60'), 6999, 500), new Item('MateBookProX', $r('app.media.mateBookProX'), 13999), new Item('WatchGT4', $r('app.media.watchGT4'), 1438), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999), new Item('FreeBuds Pro3', $r('app.media.freeBudsPro3'), 1499), new Item('Mate X5', $r('app.media.mateX5'), 12999) ] build() { Column({ space: 8 }) { // 标题部分 Header({title: '商品列表'}) .margin({ bottom: 20 }) // 自定义组件是可以加样式的 // 商品部分 List({space: 8}) { ForEach( this.items, (item: Item) => { ListItem(){ this.ItemCard(item) } } ) } } .fillScreen() } // 局部自定义构建函数 @Builder ItemCard(item: Item) { Row({space: 10}){ Image(item.image) .width(100) Column({space: 4}){ if(item.discount){ Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('原价:¥'+ item.price) .fontColor('#CCC') .fontSize(14) .decoration({type: TextDecorationType.LineThrough}) Text('折扣价:¥' + item.discount) .priceText() Text('补贴:¥ ' + (item.price - item.discount) ) .priceText() }else { Text(item.name) .fontSize(20) .fontWeight(FontWeight.Bold) Text('¥'+ item.price) .priceText() } } .height('100%') .alignItems(HorizontalAlign.Start) } .width('100%') .backgroundColor('#FFF') .borderRadius(20) .height(120) .padding(20) } // 局部位公共样式函数 @Styles fillScreen(){ .width('100%') .height('100%') .backgroundColor('#EFEFEF') .padding(20) } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。