02ArkTS语言、组件、自定义组件

ArkTS语言

  • 了解ArkTS语言特点
  • TypeScript语法

传统开发,结构,样式,行为
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
TypeScript语法去查看我的其他文章

快速入门

  • Hello World
  • 基础概念

创建工程选着模板
在这里插入图片描述
在这里插入图片描述
对文件详细介绍
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

基础组件

  • 基础组件用法
  • resource资源访问

接下来,我们来根据下面的效果来,学习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

   Image($r('app.media.icon'))
          .width(250)
          .interpolation(ImageInterpolation.High) // 抗锯齿(不用记忆直接找文档,提示也有)

Text组件

在这里插入图片描述

下图这种方式,直接写死
在这里插入图片描述
我们可以根据语言环境动态显示文本,到底是中文还是英文,要先写提示词
文件读取顺序先到,限定词目录里读取,找不到再到base里读取
所以要在限定词目录里写数据还要再base里写数据(一份数据写三次)

在限定次目录里,写提示词
在这里插入图片描述

在这里插入图片描述
在base里写提示词
在这里插入图片描述
上面这种方式在在,三个不同的json文件里配置,太麻烦,我们有办法,一下都配置好(下面讲)

动态显示文本
在这里插入图片描述

切换环境
在这里插入图片描述

TextIput文本输入框

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


@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组件

在这里插入图片描述
在这里插入图片描述


@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组件

在这里插入图片描述
在这里插入图片描述


@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
        })
    }

  }
}

页面布局

Column 和 Row

  • 线性布局组件
  • 常见布局属性

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
交叉轴默认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%')
  }
}

在这里插入图片描述

渲染控制

  • ForEach
  • if-else

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
准备基础样式结构
在这里插入图片描述

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')
  }
}

在这里插入图片描述

列表布局

  • Li st基本用法
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

使用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')
  }
}

自定义组件

  • 创建自定义组件
  • @BuiLder
  • @Styles

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

      // 标题部分
      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)
}

}

在这里插入图片描述

在这里插入图片描述

  • 11
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值