HarmonyOS鸿蒙Next中关于插槽中组件传参问题

HarmonyOS鸿蒙Next中关于插槽中组件传参问题

问题描述:A组件中使用插槽传入一个builder,在这个builder中传入了B组件,在B组件构造时传入B组件所需参数,传入参数为本地变量,且初始化为空,后续有修改。

异常结果:如果传递参数为简单类型的字符串,则正常渲染,且内容为修改后的内容;如果传递参数为复杂类型(如map),修改后使用get方法传递参数,此map仍为原始未修改格式,且报undefined的jscrash异常(Error message:Cannot read property get of undefined)

具体demo如下:

主页面:

import { DemoComp } from '../component/DemoComp';
import { ParamComp } from '../component/ParamComp';

@Entry
@ComponentV2
struct Index {
  @Local message: string = '这里是插槽组件';
  @Local paramMap: Map<string, string> = new Map();

  aboutToAppear(): void {
    this.paramMap.set('test', '插槽传参');
    this.message = '修改后的插槽参数'
  }

  @Builder
  demoBuilder(param: string) {
    if (param === 'test') {
      ParamComp({ text: this.paramMap.get(param) })
      // ParamComp({ text: this.message })
    }
  }

  build() {
    RelativeContainer() {
      Text(this.message)
        .id('builder-comp传参demo')
        .fontSize($r('app.float.page_text_font_size'))
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
      //使用A组件
      DemoComp({
        builder: this.demoBuilder //传入插槽
      })
    }
    .height('100%')
    .width('100%')
  }
}

A组件(使用插槽组件):

@ComponentV2
export struct DemoComp {
  @BuilderParam builder: (parma: string) => void

  build() {
    Column() {
      Text('这里是复用组件')
      this.builder('test')
    }
    .align(Alignment.Center)
    .width("100%")
    .height("100%")
  }
}

B组件(传入参数组件):

@ComponentV2
export struct ParamComp {
  @Param text: string = ''

  build() {
    Column() {
      Text(this.text)
    }
    .width("100%")
    .height("100%")
  }
}

更多关于HarmonyOS鸿蒙Next中关于插槽中组件传参问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

6 回复

1、执行了传递简单类型:

ParamComp({ text: this.message })

结果是:不报错,但是并没有将主页面定义的 message 传递给 B 组件

cke_5991.png

2、执行了传递 map

ParamComp({ text: this.paramMap.get(param) })

结果是:报错

cke_9911.png

3、结论:

主页面的 aboutToAppear 方法,通过 this 去给 map 赋值

在 demoBuilder 方法中,通过 this 获取值

两个 this 指向的应该不是同一个。所以在 demoBuilder 中,通过 this 拿不到主页面定义的 map,然后还用了链式调用,直接去 get,自然就报 undefined 了

可以打断点,看一下两个 this 的值,就明白了

更多关于HarmonyOS鸿蒙Next中关于插槽中组件传参问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


大佬,还是有两个问题想问一下:

1、这里的两个this为啥不是同一个,我尝试用provider和consumer传的话是可以正常接受到值的,但是这种传参的方式不行

2、如果有这种场景的话,是只能通过provider和consumer传值吗,有其他方法吗,

因为你是在主页面传了 demoBuilder 方法给 A 组件 方法虽然写在主页面,但是 A 组件也只是复用代码,并不是调用的主页面内的代码 至于 provider 和 consumer,可以看下官方文档: 官方文档 里面有说:

开发者在使用@Provider@Consumer时要注意: @Provider@Consumer强依赖自定义组件层级,@Consumer会因为所在组件的父组件不同,而被初始化为不同的值。 @Provider@Consumer相当于把组件粘合在一起了,从组件独立角度考虑,应减少使用@Provider@Consumer

也就是,你的主页面、A、B有层级关系,那么可以传过去。而不是因为你的 demoBuilder 方法 望采纳,

嘿,我又来了

参考官方文档:@BuilderParam装饰器:引用@Builder函数

其中详细说了this的指向问题

为了解决该问题,可在主页面调用A组件时,传递 builder 函数时,换个方式:

DemoComp({
  builder: () => {this.demoBuilder() //传入插槽}
})

这样就可以解决你的问题了

在HarmonyOS Next中,插槽组件传参通过@Provide@Consume装饰器实现双向同步。@Provide修饰的变量在祖先节点中提供数据,@Consume在子组件中消费对应数据。当插槽内容需要访问宿主组件状态时,使用@BuilderParam构建插槽内容,通过参数传递数据。插槽组件内部直接使用@Consume变量即可响应式更新数据,无需显式传参。这种机制实现了跨层级的组件数据通信,且保证类型安全。

在HarmonyOS Next中,插槽传参时复杂类型数据(如Map)的更新机制与简单类型不同。当使用@BuilderParam传递复杂对象时,其引用在初始化后被缓存,导致后续修改无法同步到插槽内组件。

问题分析:

  1. 简单类型(字符串)通过值传递,能够正常响应更新
  2. 复杂类型(Map)通过引用传递,但Builder执行时捕获的是初始引用
  3. 当paramMap在aboutToAppear中修改后,demoBuilder中访问的this.paramMap仍然是原始Map对象

解决方案: 使用状态管理确保复杂类型数据的响应式更新:

@Entry
@ComponentV2
struct Index {
  @State message: string = '这里是插槽组件'
  @State paramMap: Map<string, string> = new Map()

  aboutToAppear(): void {
    this.paramMap.set('test', '插槽传参')
    this.message = '修改后的插槽参数'
  }

  @Builder
  demoBuilder(param: string) {
    if (param === 'test') {
      ParamComp({ text: this.paramMap.get(param) ?? '' })
    }
  }

  // build方法保持不变
}

关键改进:

  • @Local改为@State装饰器,确保数据变化触发UI更新
  • 添加空值保护(?? '')避免undefined异常
  • State管理的Map更新会触发依赖组件的重新渲染

这样修改后,复杂类型数据在插槽中的传参就能正确响应更新,避免jscrash异常。

回到顶部