HarmonyOS 鸿蒙Next Web 同层组件如何设置自适应高度

发布于 1周前 作者 gougou168 最后一次编辑是 5天前 来自 鸿蒙OS

HarmonyOS 鸿蒙Next Web 同层组件如何设置自适应高度

背景是在 Web 中基于同层机制渲染了一个 TextArea 的组件,想实现随着 TextArea 随着内容的输入高度自适应,但遇到一个问题:

如果不显示的指定 embed 标签的高度(比如设置 auto),会导致最终计算出来的高度为 0,无法显示;但如果设置了具体的高度,比如 100px, TextArea 无法随着输入自动增加高度。

效果图:

示例 html:

示例 html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>同层渲染测试html</title>
</head>
<body>
<h1>同层渲染测试</h1>
<div class="main">
    <p>
        ChatGPT,全称聊天生成预训练转换器[2](英语:Chat Generative Pre-trained
        Transformer[3]),是OpenAI开发的人工智能聊天机器人程序,于2022年12月推出。该程序使用基于GPT-3.5、GPT-4、GPT-4o架构的大型语言模型并以强化学习训练。ChatGPT目前仍以文字方式交互,而除了可以用人类自然对话方式来交互,还可以用于甚为复杂的语言工作,包括自动生成文本、自动问答、自动摘要等多种任务。如:在自动文本生成方面,ChatGPT可以根据输入的文本自动生成类似的文本(剧本、歌曲、企划等),在自动问答方面,ChatGPT可以根据输入的问题自动生成答案。还有编写和调试计算机程序的能力。[4]在推广期间,所有人可以免费注册,并在登录后免费使用ChatGPT与AI机器人对话[5]。
    </p>
    <embed id="1" type="native/textarea" style="width: 100%; height: 100px"/>
    <p>
        ChatGPT是生成型预训练变换模型(GPT),在GPT-3.5之上用基于人类反馈的监督学习和强化学习微调。[16]这两种方法都用人类教练来提高模型性能,以人类干预增强机器学习效果,获得更逼真的结果[17]。在监督学习的情况下为模型提供这样一些对话,在对话中教练充当用户和AI助理两种角色。在强化步骤中,人类教练首先为模型在先前对话中建立的响应评级。这些级别用于建立“奖励模型”,使用近端策略优化(PPO)的多次迭代来微调[18][19]。这种策略优化算法比信任域策略优化(trust
        region policy optimization)算法更为高效[20][21]。
    </p>
</div>
</body>
</html>
复制
Ark 代码:

@Entry
@Component
struct Index {
  private webviewController = new webview.WebviewController();
  @State componentIdArr: Array<String> = [];
  private componentIdToNodeController: Map<String, ComponentNodeController> = new Map();

  build() {
    Stack() {
      ForEach(this.componentIdArr, (componentId: string) => {
        NodeContainer(this.componentIdToNodeController.get(componentId))
      }, (componentId: string) => componentId)
      Web({ src: $rawfile('test.html'), controller: this.webviewController })
        .width('100%')
        .enableNativeEmbedMode(true)
        .registerNativeEmbedRule('embed', 'native')
        .onNativeEmbedLifecycleChange((embed) => {
          const componentId = embed.info?.id?.toString() as string
          if (embed.status === NativeEmbedStatus.CREATE) {
            let nodeController = new ComponentNodeController();
            nodeController.setRenderOption({
              surfaceId: embed.surfaceId as string,
              renderType: NodeRenderType.RENDER_TYPE_TEXTURE,
              embedId: embed.embedId as string,
              width: px2vp(embed.info?.width),
              height: px2vp(embed.info?.height),
            });
            nodeController.rebuild();

            this.componentIdToNodeController.set(componentId, nodeController);
            this.componentIdArr.push(componentId);
          } else if (embed.status === NativeEmbedStatus.UPDATE) {
            let nodeController = this.componentIdToNodeController.get(componentId);
            nodeController?.updateNode({
              width: px2vp(embed.info?.width),
              height: px2vp(embed.info?.height),
            } as ESObject);
            nodeController?.rebuild();
          } else {
            let nodeController = this.componentIdToNodeController.get(componentId);
            nodeController?.setBuilderNode(null);
            nodeController?.rebuild();
          }
        })
        .onNativeEmbedGestureEvent((touch) => { // 获取同层渲染组件触摸事件信息
          this.componentIdArr.forEach((componentId) => {
            let nodeController = this.componentIdToNodeController.get(componentId);
            if (nodeController?.getEmbedId() === touch.embedId) {
              nodeController?.postTouchEvent(touch.touchEvent);
            }
          })
        })
    }
    .height('100%')
    .margin({ top: '107px' })
  }
}

declare class ComponentNodeControllerParams {
  surfaceId: string
  renderType: NodeRenderType
  embedId: string
  width: number
  height: number
  position?: Position
}

class ComponentNodeController extends NodeController {
  private rootNode: BuilderNode<ComponentParams[]> | undefined | null;
  private surfaceId: string = "";
  private renderType: NodeRenderType = NodeRenderType.RENDER_TYPE_DISPLAY;
  private embedId: string = "";
  private componentWidth: number = 0;
  private componentHeight: number = 0;

  setRenderOption(params: ComponentNodeControllerParams) {
    hilog.info(0x0000, TAG, `setRenderOption: ${JSON.stringify(params)}`)
    this.surfaceId = params.surfaceId;
    this.renderType = params.renderType;
    this.embedId = params.embedId;
    this.componentWidth = params.width;
    this.componentHeight = params.height;
  }

  makeNode(uiContext: UIContext): FrameNode | null {
    if (!this.rootNode) {
      this.rootNode = new BuilderNode(uiContext, { surfaceId: this.surfaceId, type: this.renderType });
      this.rootNode.build(wrapBuilder(TextAreaComponentBuilder), {
        width: this.componentWidth,
        height: this.componentHeight,
      });
    }
    return this.rootNode.getFrameNode();
  }

  setBuilderNode(rootNode: BuilderNode<ComponentParams[]> | null): void {
    this.rootNode = rootNode;
  }

  updateNode(arg: Object): void {
    this.rootNode?.update(arg);
  }

  getEmbedId(): string {
    return this.embedId;
  }

  postTouchEvent(event: TouchEvent | undefined): boolean {
    return this.rootNode?.postTouchEvent(event) as boolean
  }
}

declare class ComponentParams {
  width: number
  height: number
}

@Builder
function TextAreaComponentBuilder(params: ComponentParams) {
  TextAreaComponent({
    componentWidth: params.width,
    componentHeight: params.height,
  })
}

@Component
struct TextAreaComponent {
  componentWidth?: number
  componentHeight?: number
  private controller = new TextAreaController();

  build() {
    Column() {
      TextArea({ placeholder: "TextArea", controller: this.controller })
        .width('100%')
        .fontSize(18)
    }
    .width('100%')
  }
}
2 回复
TextArea组件不设置height属性时,可自适应最大高度,另外可以用constraintSize({minHeight: 50})设置最小高度,此时最大高度也会自适应

针对HarmonyOS 鸿蒙Next Web同层组件设置自适应高度的问题,以下是一些专业建议:

  1. CSS布局支持:确保H5页面使用了能够支持高度自适应的CSS布局,如Flexbox或Grid布局。同时,在CSS中设置html, body { height: 100%; },以确保容器可以扩展到视窗高度。
  2. JavaScript动态调整:在H5页面的body底部动态添加一个div元素,利用该元素的offsetTop属性值来确定Web组件的高度,并据此调整父容器的高度。可以通过JavaScript获取新元素的高度,并手动调整容器高度,但更常见的是使用CSS的min-height或flex-grow等属性来自动调整。
  3. 监听窗口变化:使用window.onresize事件监听器,确保在窗口大小变化时,动态调整的元素也能相应地调整其大小或位置。
  4. nestedScroll属性:在Scroll组件中嵌套Web组件时,应使用nestedScroll属性,并设置layoutMode为followSystem或followContent,同时确保Web组件有明确的宽度设置。

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

回到顶部