一、关于样式

1 . 默认单位 vp

答: vp 是 virtual pixel 的缩写,根据设备像素密度转化为屏幕物理像素,px 直接表示设备的像素,因为我们设备的分辨率密度不同,最好是使用 vp

适配: 可以使用伸缩布局layoutWeight,flex布局,网格系统,栅格系统布局,

2 . 写公共样式

在开发过程中会出现大量代码在进行重复样式设置,@Styles 和 Extend 可以帮我们进行样式复用

1. @styles 方式

  • 只支持通用属性 和 通用事件,且不支持箭头函数语法
  • 在组件内(局部)无需加 function , 在组件外(全局) 定义时要加function
@Styles function textStyle () {
  .width(100)
  .height(50)
  .backgroundColor(Color.Pink)
  .borderRadius(25)
  .onClick(() => {
    promptAction.showToast({
       message: "测试"
    })
  })
}

2. Extend 方式

  • 使用 @Extend 装饰器修饰的函数只能是 全局
  • 且参数可以是一个函数,实现复用事件且可处理不同逻辑
  • 函数可以进行 传参,如果参数是状态变量,状态更新后会刷新UI
// 全局  原生组件                     参数
//  ↓     ↓                          ↓ 
@Extend(Text) function textInputAll (callback?: () => void) {
  .width(100)
  .height(50)
  .backgroundColor(Color.Pink)
  .borderRadius(25)
  .textAlign(TextAlign.Center)
  .fontColor(Color.White)
  .onClick(() => {
    callback && callback()
  })
}

二 、 加载图片

  1. 使用本地图片
// 可以新建一个文件夹,里面放本地图片(ets下)
Image('/assets/a.png')
  1. 使用 resource 下的 media 图片
// resource/media  (a 是文件名,扩展名省略)
Image($r('/app.media.a'))
  1. 使用 resource 下的 rawfile 图片
// resource/rawfile
Image($rawfile('a.png'))
  1. 使用网络图片(必须申请网络权限)
// resource/rawfile
Image("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F2bf1b169-d217-44c3-a5b3-dd00813bc20d%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1704614176&t=e15a2fd5193aeeb24fc95b5dbe395907")
"requestPermissions": [{
  "name":"ohos.permission.INTERNET"
}],

三 、 父子组件传值

  • 父传子
// 父组件的子组件上,传递一个对象(HmCommentItem)
   HmCommentItem({ item:item})
// 子组件上进行接收
  item: Partial<ReplyItem> = {} // 默认是public
  • 子传父(目的是修改父组件的值)
// 父组件的子组件上,传递一个方法(HmCommentItem)
 HmCommentItem({ item:item,changeLike:(item)=>{
                this.changeLike(item)
              }})
// 子组件上进行接收
changeLike: (params: ReplyItem) => void = () => {} // 接受一个无返回值的方法,默认是空函数

四 、 自定义构建函数 @Builder

  1. 使用@Builder 定义一个函数(全局加function)
  2. 在组件里使用这个函数
// 定义 Builder
@Builder
function getCellContent(leftTitle: string, rightValue: string) {
  Row() {
    Row() {
      Text(leftTitle)
      Text(rightValue)
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceBetween)
    .padding({
      left: 15,
      right: 15
    })
    .borderRadius(8)
    .height(40)
    .backgroundColor(Color.White)
  }.padding({
    left: 10,
    right: 10
  })

}
class CardClass {
  time: string = ""
  location: string = ""
  type: string = ""
}
@State formData: CardClass = {
    time: "2023-12-12",
    location: '回龙观',
    type: '漏油'
  }
// 在组件里使用
Column({ space: 10 }) {
        getCellContent("异常时间", this.formData.time)
        getCellContent("异常位置", this.formData.location)
        getCellContent("异常类型", this.formData.type)
        
        Button("修改数据").onClick(() => {
          this.formData.location = "望京"
        })
      }
      .width('100%')

全局自定义函数的问题

  1. 全局的自定义构建函数可以被整个应用获取(下一代可用-当前4.0暂不支持),不允许使用this和bind方法。

  2. 不可被其他文件引用

  3. 当我点击按钮时数据即使是响应式的,当数据发生改变,该函数不会自动渲染

    • 因为我们刚刚传过去的是一个string类型, string 类型是一个基础类型,按值传递,不具备响应式更新的特点 解决方案:改为按引用传递
// 完整代码
@Entry
@Component
struct BuilderCase {
  @State formData: CardClass = {
    time: "2023-12-12",
    location: '回龙观',
    type: '漏油'
  }
  @Builder
  getCellContent($$: CellParams) {
    Row() {
      Row() {
        Text($$.leftTitle)
        Text($$.rightValue)
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
      .padding({
        left: 15,
        right: 15
      })
      .borderRadius(8)
      .height(40)
      .backgroundColor(Color.White)
    }.padding({
      left: 10,
      right: 10
    })

  }
  build() {
    Row() {
      Column() {
        Column({ space: 10 }) {
          this.getCellContent({ leftTitle: '异常时间', rightValue: this.formData.time })
          this.getCellContent({ leftTitle: '异常位置', rightValue: this.formData.location })
          this.getCellContent({ leftTitle: '异常类型', rightValue: this.formData.type })
        }
        .width('100%')
        Button("修改数据").onClick(() => {
          this.formData.location = "望京"
        })
      }
      .width('100%')
    }
    .height('100%')
    .backgroundColor('#ccc')
  }
}

class CardClass {
  time: string = ""
  location: string = ""
  type: string = ""
}
class CellParams {
  leftTitle: string = ""
  rightValue: string = ""
}

五、构建函数-@BuilderParam 传递UI

  1. 使用@BuilderParam 声明一个组件,子组件要在想要显示插槽的地方来调用传入的方法
  2. 在父组件里调用并传入,父组件传递是一个函数,这个函数也要使用 @Builder 修饰
// 使用BuilderParam 声明组件
@Component
struct  HMCard {
  @BuilderParam
  content: () => void
  build() {
    Column () {
      Text("卡片组件")
      Divider()
      Text("传入内容")
      if(this.content) {
        this.content()  // 子组件要在想要显示插槽的地方来调用传入的方法
      }
    }
  }
}
@Entry
@Component
struct BuilderParamCase {
// 声明渲染的函数组件
  @Builder
  getContent () {
    Row() {
      Text("插槽内容")
        .fontColor(Color.Red)
    }
  }
  build() {
    Row() {
      Column() {
        HMCard({ content: this.getContent })  // 调用组件并传入要渲染的函数
      }
      .width('100%')
    }
    .height('100%')
  }
}
01-05 14:14