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
1、执行了传递简单类型:
ParamComp({ text: this.message })
结果是:不报错,但是并没有将主页面定义的 message 传递给 B 组件
2、执行了传递 map
ParamComp({ text: this.paramMap.get(param) })
结果是:报错
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中,插槽传参时复杂类型数据(如Map)的更新机制与简单类型不同。当使用@BuilderParam
传递复杂对象时,其引用在初始化后被缓存,导致后续修改无法同步到插槽内组件。
问题分析:
- 简单类型(字符串)通过值传递,能够正常响应更新
- 复杂类型(Map)通过引用传递,但Builder执行时捕获的是初始引用
- 当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异常。