HarmonyOS 鸿蒙Next @BuilderParam为什么无法形成父子组件关系?

发布于 1周前 作者 nodeper 来自 鸿蒙OS

HarmonyOS 鸿蒙Next @BuilderParam为什么无法形成父子组件关系?

@Component
export struct Scope {
@Provide vertical: Length = default_vertical
@Provide horizontal: Length = default_horizontal
@Provide round: Length = default_round
@BuilderParam
content: () => void

build() { Stack() { this.content() } } }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

这是父组件。

@Component
export struct AppButton {
@Consume vertical: Length
@Consume horizontal: Length
@Consume round: Length

build() { Button(‘test’) .padding({ left: this.horizontal, top: this.vertical, right: this.horizontal, bottom: this.vertical }) } }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

这是子组件。

Scope({ vertical: 10 }) {
AppIconButton()
}<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

这是用例,运行后报错:

Error message:@Component ‘AppButton’[8] missing @Provide property with name vertical.
Fail to resolve @Consume(vertical).<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

将Scope中的全部@Provide声明参数移动到@Entry级别下后成功运行。

9 回复

你的代码这种尾随闭包产生的结果是AppIconButton组合所在的上下文位置是在调用的代码作用域中,即AppIconButton的父组件成了调用时所在组件(估计是[@Entry](/user/Entry)组件),而Scope也在此位置被调用,则两者成为同级关系而非父子组件关系,因此[@Provide](/user/Provide)和[@Consume](/user/Consume)无法实现预想的效果,用简单测试可证实:

在三个组件都准备一个成员变量 label: string = 'xxx';  分别写上各位置的标记字符串,然后在尾随闭包中调用AppIconButton()前面加上Text(this.label).fontsize(20);运行代码后会看到显示的是调用AppIconButton所在组件内的label变量所指的字符串,证实这种尾随闭包编译后的效果;这和编译器处理尾随闭包的机制相关,文档没有说明,只能测试证实。

另外,把尾随闭包改换成一个普通[@Builder](/user/Builder)构建函数后再用 content: this.mBuilder 这种变量赋值方式传递给Scope则可实现预期的父子关系;当然,了解了尾随闭包的真实上下文关系,在调用组件中使用[@Provide](/user/Provide)也得到同样结果。

还真是这样,他们无法成为父子组件关系,不知道这是有意为之还是bug。

也可能开发功能时没有考虑到这么多细节组合情况,毕竟语法组合数量太大,最终效果还得看编译器具体处理,官方语法大师可能也不能确定,只有实测不骗人,而且工具在升级,同样语法不同版本可能就不一样效果了:)

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-provide-and-consume-0000001820879589#ZH-CN_TOPIC_0000001857876921__provide%E6%94%AF%E6%8C%81allowoverride%E5%8F%82%E6%95%B0

看下这个,说到了[@BuilderParam](/user/BuilderParam)使用的时候,[@Provide](/user/Provide)没有被创建的问题,感觉跟你现在遇到的问题差不多。

这个文档我无法查阅

常见问题 @BuilderParam尾随闭包情况下@Provide未定义错误 在此场景下,CustomWidget执行this.builder()创建子组件CustomWidgetChild时,this指向的是HomePage。因此找不到CustomWidget的@Provide变量,所以下面示例会报找不到@Provide错误,和@BuilderParam连用的时候要谨慎this的指向。

错误示例:

class Tmp { a: string = ‘’ }

@Entry @Component struct HomePage { @Builder builder2($$: Tmp) { Text(${$$.a}测试) }

build() { Column() { CustomWidget() { CustomWidgetChild({ builder: this.builder2 }) } } } }

@Component struct CustomWidget { @Provide(‘a’) a: string = ‘abc’; @BuilderParam builder: () => void;

build() { Column() { Button(‘你好’).onClick((x) => { if (this.a == ‘ddd’) { this.a = ‘abc’; } else { this.a = ‘ddd’; }

  })
  this.builder()
}

} }

@Component struct CustomWidgetChild { @Consume(‘a’) a: string; @BuilderParam builder: ($$: Tmp) => void;

build() { Column() { this.builder({ a: this.a }) } } }

就是这段描述

这个是this使用的问题,看看你那边有没有这种情况。 其实我觉得你遇到的问题应该是@Provide创建时机问题,这个我们也没有源码,只能靠猜了。所以你可以在build()试试,如果可以,猜就是build()创建的view才被鸿蒙认为是子view,或者是只有在build()的时候才会创建@Provide相关的注解实现。 不管怎么样,其实就是你之前这样的使用方式不对。

从你测试来看,AppButton只能在Scope的build()或者是Scope子view下才能生效;

可能是[@Provide](/user/Provide)还没有注册成功(猜测)。

Scope({ vertical: 10 }) { AppIconButton() }这个不表示AppIconButton在是Scope的build()之后才使用,因为可以放在其他view的build()里面调用;

你改成

[@Component](/user/Component) export struct Scope {

[@Provide](/user/Provide) vertical: Length = default_vertical

[@Provide](/user/Provide) horizontal: Length = default_horizontal

[@Provide](/user/Provide) round: Length = default_round

[@BuilderParam](/user/BuilderParam) content: () => void

build() {

Stack() { AppIconButton() }

}

}

试试。

没有看到完整的代码,不知道存不存在使用[@BuilderParam](/user/BuilderParam),可能存在一个this指向问题;

因为现在鸿蒙存在的问题比较多,所以还是先按照文档上中规中矩的用比较靠谱。

在HarmonyOS鸿蒙系统中,@BuilderParam注解主要用于自定义组件时,通过Builder模式来构建组件的属性。若@BuilderParam无法形成预期的父子组件关系,通常可能是以下几个原因导致的:

  1. 注解使用不当:确保@BuilderParam被正确地应用于需要构建的属性上,并且属性类型与父组件接收的类型一致。

  2. 组件定义问题:检查父子组件的定义,确保父组件能够正确解析和接收子组件。子组件的注册和导入是否正确,以及是否遵循了鸿蒙系统的组件通信和嵌套规则。

  3. XML布局文件错误:如果在XML中定义组件关系,检查是否有语法错误或标签不匹配的情况,确保父组件能够包含子组件。

  4. 版本兼容性问题:不同版本的鸿蒙系统可能对组件和注解的支持有差异,确保开发环境与目标设备系统版本兼容。

  5. 编译与运行时环境:检查开发工具的版本和配置,确保编译环境正确无误,同时运行时环境也支持所使用的组件和特性。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。

回到顶部