DEV Community

Cover image for 鸿蒙开发:wrapBuilder传递参数
程序员一鸣
程序员一鸣

Posted on

鸿蒙开发:wrapBuilder传递参数

前言

代码案例基于Api13。

在前边的文章中,关于wrapBuilder传递参数我们有过概述,无论是定义在局部还是全局,传递参数都是非常的简单,直接调用builder函数即可,简单案例如下所示:

@Builder
  function TextView(value: string) {
    Text(value)
  }


@Entry
  @Component
  struct Index {
    textBuilder: WrappedBuilder<[string]> = wrapBuilder(TextView)

    build() {
      Column() {
        this.textBuilder.builder("我是传递的参数")
      }.width("100%")
        .height("100%")
        .justifyContent(FlexAlign.Center)
    }
  }
Enter fullscreen mode Exit fullscreen mode

以上的参数,是在UI视图中传递的,传递参数是非常的简单,但是,如果不在UI视图中呢?这就是我最近遇到的问题,团队中使用了我自定义的任意位置的dialog,和下图的dialog类似,有一个需求是,message不是简单的文字,有可能是图文,有可能是富文本,也有可能是其他的展示,这种情况在接收一个文字或者其它类型就显得不够灵活了,所以,我直接把message这个组件暴露了出去,由调用者传递。

Image description

这样就解决了message丰富多样的情况,毕竟组件是调用者传递的,虽然效果实现了,但是又提了问题:

“我这个message,是根据逻辑进行展示的,比如为true展示这个,false就展示另一个,数据如何传递过去呢?”

“……呃,要求那么多,那算了,你自己定义吧”,当然了,这只是自己的心声,实际情况,还是点头说,好的,马上解决。

基本案例

案例,这里我简化了,主要是定义了一个弹窗工具类。

import { ComponentContent } from "@kit.ArkUI"
import { DialogAttribute } from "./DialogAttribute"

export class DialogUtils {
  private constructor() {
  }

  private static mDialogUtils: DialogUtils

  public static get() {
    if (DialogUtils.mDialogUtils == undefined) {
      DialogUtils.mDialogUtils = new DialogUtils()
    }
    return DialogUtils.mDialogUtils
  }

  showDialog(context: UIContext, dialogAttribute?: DialogAttribute) {
    if (dialogAttribute == undefined) {
      dialogAttribute = new DialogAttribute()
    }
    this.show(context, dialogAttribute)
  }

  private show(context: UIContext, object: Object) {
    let dView = wrapBuilder<Object[]>(dialogView)
    let dialogContent: ComponentContent<Object> = new ComponentContent(context, dView, object)
    context.getPromptAction().openCustomDialog(dialogContent)
  }
}

@Builder
  function dialogView(dialogAttribute?: DialogAttribute) {
    Column() {
      Text(dialogAttribute?.title)
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 10 })

      //message是一个组件视图
      if (dialogAttribute?.messageView != undefined) {
        dialogAttribute?.messageView.builder()
      }

      Row() {
        Text("取消")
          .height(40)
          .textAlign(TextAlign.Center)
          .layoutWeight(1)
        Text("确定")
          .height(40)
          .layoutWeight(1)
          .textAlign(TextAlign.Center)
      }.width("100%")
    }.width("80%")
      .backgroundColor(Color.White)
      .borderRadius(10)
  }
Enter fullscreen mode Exit fullscreen mode

在实际的开发中,很多的内容都是动态可变的,也需要把这些属性暴露出去,这里我简单定义了一个属性文件,在实际的开发中,会有很多的属性,这里,我简单的定义了两个,主要是用于测试。

export class DialogAttribute {
  title?: 
  messageView?: WrappedBuilder<Object[]>
}
Enter fullscreen mode Exit fullscreen mode

直接调用:

import { DialogUtils } from './DialogUtils'

@Builder
function messageView() {

  Text("简单测试")
    .margin({ top: 20, bottom: 20 })
}

@Entry
@Component
struct Index {
  build() {
    Column() {
      Button("点击")
        .onClick(() => {
          DialogUtils.get()
            .showDialog(this.getUIContext(), {
              title: "我是dialog弹窗",
              messageView: wrapBuilder(messageView)
            })
        })
    }.width("100%")
    .height("100%")
    .justifyContent(FlexAlign.Center)
  }
}
Enter fullscreen mode Exit fullscreen mode

通过以上的案例,我们就简单搞了一个自定义弹窗,点击按钮之后,就会弹出一个弹窗,支持message消息自定义组件,实现任意的效果。

话说回来,我如何在全局的@Builder里接收参数呢?也就是下面的位置中:

@Builder
function messageView() {

  Text("简单测试")
    .margin({ top: 20, bottom: 20 })
}
Enter fullscreen mode Exit fullscreen mode

传递参数

方式一,中间中转

所谓中间中转,我们可以在一个类中,定义一个变量,用于接收传递的数据,这是最简单的,这边传递的时候赋值,那边使用的时候取出。

定义赋值变量:

  private mParams?: Object

  private setData(params?: Object) {
    this.mParams = params
  }

  getData(): Object | undefined {
    return this.mParams
  }
Enter fullscreen mode Exit fullscreen mode

接收数据的时候,进行赋值

  showDialog(context: UIContext, dialogAttribute?: DialogAttribute) {
    if (dialogAttribute == undefined) {
      dialogAttribute = new DialogAttribute()
    }
    //设置数据
    this.setData(dialogAttribute.messageData)
    this.show(context, dialogAttribute)
  }
Enter fullscreen mode Exit fullscreen mode

使用:

@Builder
function messageView() {
  //这里接收传递的参数
  Text(DialogUtils.get().getData()?.toString())
    .margin({ top: 20, bottom: 20 })
}
Enter fullscreen mode Exit fullscreen mode

有一点需要知道,那就是如果多个弹窗共用,赋值变量是单列或者静态的时候,在dialog销毁的时候记得恢复原值。

方式二,直接接收

因为把wrapBuilder传递给了ComponentContent对象职中,在wrapBuilder中使用wrapBuilder时,发现会直接携带参数,我们直接使用即可。

 let dView = wrapBuilder<Object[]>(dialogView)
  let dialogContent: ComponentContent<Object> = new ComponentContent(context, dView, object)
  context.getPromptAction().openCustomDialog(dialogContent)
Enter fullscreen mode Exit fullscreen mode

定义接收参数

在属性定义文件中,定义我们需要接收的数据,由于数据的类型不确定,这里我们可以直接定义为一个Object。

Image description

传递数据

DialogUtils.get()
            .showDialog(this.getUIContext(), {
              title: "我是dialog弹窗",
              messageView: wrapBuilder(messageView),
              messageData: "简单传递一个字符串"
            })
Enter fullscreen mode Exit fullscreen mode

直接接收传递的对象,获取到指定的字段参数即可。

@Builder
function messageView(attr: DialogAttribute) {
  //这里接收传递的参数
  Text(attr.messageData?.toString())
    .margin({ top: 20, bottom: 20 })
}
Enter fullscreen mode Exit fullscreen mode

相关总结

本文,主要简单了介绍了一下,非UI使用的情况下,wrapBuilder传递数据问题,除了以上的方式之外,还有其它的方式可以实现,在实际的开发中,还是具体问题具体分析。

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay