HarmonyOS 同层渲染的组件内,可以再使用自定义的组件吗?

​同层渲染,参照文档:​https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/web-same-layer-V5​在自定义NodeController中的makeNode方法,返回FrameNode节点时,创建同层渲染组件。

this.rootNode.build(wrapBuilder(myBuilder), {xxxx})

在myBuilder构造函数中,返回同层渲染组件EmbedView。​

@Component 
struct EmbedView { 
  build() { 
    xxxx 
  } 
}

在EmbedView中又使用了自定义组件MyImage。

@Component 
struct MyImage { 
  build() { 
    xxxx 
  } 
}

这个自定义组件MyImage就会不展示。问题是:在同层渲染的组件内,可以再使用自定义的组件吗?

HarmonyOS
2024-11-05 10:57:08
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
superinsect

本地测试是可以使用自定义组件。测试demo:

// 1、 Index.ets 
// 创建NodeController 
import webview from '@ohos.web.webview'; 
import { UIContext } from '@ohos.arkui.UIContext'; 
import { NodeController, BuilderNode, NodeRenderType, FrameNode } from "@ohos.arkui.node"; 
@Observed 
declare class Params { 
  textOne: string 
  textTwo: string 
  width: number 
  height: number 
} 
declare class nodeControllerParams { 
  surfaceId: string 
  type: string 
  renderType: NodeRenderType 
  embedId: string 
  width: number 
  height: number 
} 
// 用于控制和反馈对应的NodeContainer上的节点的行为,需要与NodeContainer一起使用。 
class MyNodeController extends NodeController { 
  private rootNode: BuilderNode<[Params]> | undefined | null; 
  private embedId_: string = ""; 
  private surfaceId_: string = ""; 
  private renderType_: NodeRenderType = NodeRenderType.RENDER_TYPE_DISPLAY; 
  private width_: number = 0; 
  private height_: number = 0; 
  private type_: string = ""; 
  private isDestroy_: boolean = false; 
  setRenderOption(params: nodeControllerParams) { 
    this.surfaceId_ = params.surfaceId; 
    this.renderType_ = params.renderType; 
    this.embedId_ = params.embedId; 
    this.width_ = params.width; 
    this.height_ = params.height; 
    this.type_ = params.type; 
  } 
  // 必须要重写的方法,用于构建节点数、返回节点数挂载在对应NodeContainer中。 
  // 在对应NodeContainer创建的时候调用、或者通过rebuild方法调用刷新。 
  makeNode(uiContext: UIContext): FrameNode | null { 
    if (this.isDestroy_) { // rootNode为null 
      return null; 
    } 
    if (!this.rootNode) { // rootNode 为undefined时 
      this.rootNode = new BuilderNode(uiContext, { surfaceId: this.surfaceId_, type: this.renderType_ }); 
      if (this.type_ === 'native/button') { 
        this.rootNode.build(wrapBuilder(ButtonBuilder), { 
          textOne: "myButton1", 
          textTwo: "myButton2", 
          width: this.width_, 
          height: this.height_ 
        }); 
      } else { 
        // other 
      } 
    } 
    // 返回FrameNode节点。 
    return this.rootNode.getFrameNode(); 
  } 
  setBuilderNode(rootNode: BuilderNode<Params[]> | null): void { 
    this.rootNode = rootNode; 
  } 
  getBuilderNode(): BuilderNode<[Params]> | undefined | null { 
    return this.rootNode; 
  } 
  updateNode(arg: Object): void { 
    this.rootNode?.update(arg); 
  } 
  getEmbedId(): string { 
    return this.embedId_; 
  } 
  setDestroy(isDestroy: boolean): void { 
    this.isDestroy_ = isDestroy; 
    if (this.isDestroy_) { 
      this.rootNode = null; 
    } 
  } 
  postEvent(event: TouchEvent | undefined): boolean { 
    return this.rootNode?.postTouchEvent(event) as boolean 
  } 
} 
@Component 
struct ImageComponent { 
  @ObjectLink params: Params 
  build() { 
    Column() { 
      Image($r('app.media.app_icon')) 
        .width(80).height(40) 
    } 
  } 
} 
@Component 
struct ButtonComponent { 
  @ObjectLink params: Params 
  @State bkColor: Color = Color.Red 
  build() { 
    Column() { 
      Button(this.params.textOne) 
        .border({ width: 2, color: Color.Red }) 
        .backgroundColor(this.bkColor) 
 
      Button(this.params.textTwo) 
        .border({ width: 2, color: Color.Red }) 
        .backgroundColor(this.bkColor) 
 
      ImageComponent({ params: this.params }) 
    } 
    .width(this.params.width) 
    .height(this.params.height) 
  } 
} 
// @Builder中为动态组件的具体组件内容。 
@Builder 
function ButtonBuilder(params: Params) { 
  ButtonComponent({ params: params }) 
    .backgroundColor(Color.Green) 
} 
@Entry 
@Component 
struct WebIndex { 
  browserTabController: WebviewController = new webview.WebviewController() 
  private nodeControllerMap: Map<string, MyNodeController> = new Map(); 
  @State componentIdArr: Array<string> = []; 
 
  aboutToAppear() { 
    // 配置web开启调试模式。 
    webview.WebviewController.setWebDebuggingAccess(true); 
  } 
  build() { 
    Row() { 
      Column() { 
        Stack() { 
          ForEach(this.componentIdArr, (componentId: string) => { 
            NodeContainer(this.nodeControllerMap.get(componentId)) 
          }, (embedId: string) => embedId) 
          // web组件加载本地test.html页面。 
          Web({ src: $rawfile("test.html"), controller: this.browserTabController })// 配置同层渲染开关开启。 
            .enableNativeEmbedMode(true)// 获取embed标签的生命周期变化数据。 
            .onNativeEmbedLifecycleChange((embed) => { 
              // 获取web侧embed元素的id。 
              const componentId = embed.info?.id?.toString() as string 
              if (embed.status == NativeEmbedStatus.CREATE) { 
                // 创建节点控制器,设置参数并rebuild。 
                let nodeController = new MyNodeController() 
                nodeController.setRenderOption({ 
                  surfaceId: embed.surfaceId as string, 
                  type: embed.info?.type as string, 
                  renderType: NodeRenderType.RENDER_TYPE_TEXTURE, 
                  embedId: embed.embedId as string, 
                  width: px2vp(embed.info?.width), 
                  height: px2vp(embed.info?.height) 
                }) 
                nodeController.setDestroy(false); 
                // 根据web传入的embed的id属性作为key,将nodeController存入map。 
                this.nodeControllerMap.set(componentId, nodeController) 
                // 将web传入的embed的id属性存入@State状态数组变量中,用于动态创建nodeContainer节点容器,需要将push动作放在set之后。 
                this.componentIdArr.push(componentId) 
              } else if (embed.status == NativeEmbedStatus.UPDATE) { 
                let nodeController = this.nodeControllerMap.get(componentId) 
                nodeController?.updateNode({ 
                  textOne: 'update', 
                  width: px2vp(embed.info?.width), 
                  height: px2vp(embed.info?.height) 
                } as ESObject) 
              } else { 
                let nodeController = this.nodeControllerMap.get(componentId); 
                nodeController?.setDestroy(true) 
                this.nodeControllerMap.clear(); 
                this.componentIdArr.length = 0; 
              } 
            })// 获取同层渲染组件触摸事件信息。 
            .onNativeEmbedGestureEvent((touch) => { 
              this.componentIdArr.forEach((componentId: string) => { 
                let nodeController = this.nodeControllerMap.get(componentId) 
                if (nodeController?.getEmbedId() === touch.embedId) { 
                  let ret = nodeController?.postEvent(touch.touchEvent) 
                  if (ret) { 
                    console.log("onNativeEmbedGestureEvent success " + componentId) 
                  } else { 
                    console.log("onNativeEmbedGestureEvent fail " + componentId) 
                  } 
                } 
              }) 
            }) 
        } 
      } 
    } 
  } 
}
// 2、test.html 
<!Document> 
<html> 
<head> 
    <title>同层渲染测试html</title> 
    <meta name="viewport"> 
</head> 
<body> 
<div> 
    <div id="bodyId"> 
        <embed id="nativeButton" type = "native/button" width="800" height="800" src="test?params1=xxx?" style = "background-color:red"/> 
    </div> 
</div> 
<div id="button" width="500" height="200"> 
    <p>bottom</p> 
</div> 
</body> 
</html>
分享
微博
QQ
微信
回复
2024-11-05 15:23:32
相关问题
HarmonyOS C++自定义组件如何开发?
237浏览 • 1回复 待解决
自定义组件onMeasureSize使用
301浏览 • 1回复 待解决
HarmonyOS WebView实现渲染资料
292浏览 • 1回复 待解决
HarmonyOS ArkWeb渲染嵌套能力
407浏览 • 1回复 待解决
webview是否支持渲染
1771浏览 • 1回复 待解决
HarmonyOS如何自定义组件Controller?
219浏览 • 1回复 待解决
HarmonyOS 自定义组件事件处理
297浏览 • 1回复 待解决
自定义组件嵌套子组件
9359浏览 • 3回复 待解决
HarmonyOS 自定义组件问题
295浏览 • 1回复 待解决