在 HarmonyOS(鸿蒙)应用开发中,纯 ArkTS 组件有时难以满足复杂富文本展示、动态 HTML 渲染等场景需求,而 H5 在排版灵活性、富文本处理上具备天然优势。此时通过Web组件实现 ArkTS(鸿蒙侧)与 H5(前端侧)的交互,成为混合开发的核心方案。本文将基于你提供的核心代码,从「H5 侧资源准备」「鸿蒙侧调用 JS 函数」两个维度,详解鸿蒙与 H5 的单向交互实现,以及背后的核心原理。

一、交互场景与核心原理

1. 典型应用场景

当鸿蒙应用需要展示动态生成的富文本内容(如答题结果、商品详情、协议条款)时,直接用 ArkTS 组件拼接 HTML 标签易出错且样式难控,而将 HTML 渲染逻辑交给 H5,鸿蒙侧仅需传递数据并触发渲染,能大幅降低开发成本。

2. 核心交互原理

鸿蒙侧通过Web组件加载本地 / 远程 H5 页面,借助WebController控制器的runJavaScript()方法,调用 H5 页面中预定义的 JS 函数,实现「鸿蒙侧传数据、H5 侧渲染内容」的单向交互。整体流程如下:

预览

查看代码

1. 加载H5页面

2. 页面加载完成

3. 调用runJavaScript

4. 渲染HTML内容

鸿蒙侧

Web组件

触发onPageEnd回调

H5侧JS函数

H5页面显示数据

flowchart LR
    A[鸿蒙侧] -->|1. 加载H5页面| B[Web组件]
    B -->|2. 页面加载完成| C[触发onPageEnd回调]
    C -->|3. 调用runJavaScript| D[H5侧JS函数]
    D -->|4. 渲染HTML内容| E[H5页面显示数据]

1. 加载H5页面

2. 页面加载完成

3. 调用runJavaScript

4. 渲染HTML内容

鸿蒙侧

Web组件

触发onPageEnd回调

H5侧JS函数

H5页面显示数据

二、完整实现步骤(鸿蒙侧 + H5 侧)

第一步:H5 侧准备(定义 HTML 资源与 JS 函数)

首先在鸿蒙项目中创建本地 HTML 文件,定义接收鸿蒙数据并渲染内容的 JS 函数,这是交互的基础。

1. 新建 HTML 资源文件

在鸿蒙项目的main/ets/rawfile目录下(无则新建),创建question.html文件(与代码中$rawfile('question.html')路径对应),内容如下:

html

预览

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>答题结果展示</title>
    <style>
        /* 自定义样式,适配鸿蒙Web组件 */
        .answer-container {
            padding: 16px;
            font-size: 16px;
            color: #333;
            line-height: 1.6;
        }
        .title {
            font-weight: bold;
            color: #007DFF;
            margin-bottom: 8px;
        }
    </style>
</head>
<body>
    <!-- 用于渲染内容的容器 -->
    <div class="answer-container" id="answerContent"></div>

    <script>
        /**
         * 鸿蒙侧调用的核心JS函数:接收HTML内容并渲染
         * @param {string} html - 鸿蒙侧传递的HTML/文本内容
         */
        function writeHtml(html) {
            // 获取容器元素,将内容插入到页面中
            const contentEl = document.getElementById('answerContent');
            // 支持HTML富文本渲染(若仅需纯文本,用textContent)
            contentEl.innerHTML = `<div class="title">答案:</div>${html}`;
        }
    </script>
</body>
</html>
2. H5 侧代码解析
  • rawfile目录:鸿蒙项目中rawfile原生资源目录,存放的文件会被打包到应用中,通过$rawfile('文件名')可直接访问,无需拼接路径;
  • writeHtml函数:鸿蒙侧调用的核心入口,接收鸿蒙传递的html参数,通过innerHTML将内容渲染到页面容器中(支持富文本,若需纯文本可替换为textContent);
  • 样式适配:通过viewport设置移动端适配,保证在鸿蒙 Web 组件中显示正常。

第二步:鸿蒙侧实现(加载 H5 并调用 JS 函数)

在 ArkTS 页面中通过Web组件加载上述 HTML 文件,监听页面加载完成事件,调用runJavaScript执行 H5 的writeHtml函数。

完整 ArkTS 代码示例

typescript

运行

// pages/AnswerPage.ets
@Entry
@Component
struct AnswerPage {
  // 1. 定义Web控制器,用于操作Web组件(如执行JS、刷新页面)
  private controller: WebController = new WebController()
  // 模拟答题数据(实际可从接口/本地存储获取)
  private item = {
    answer: '<p>鸿蒙侧传递的<span style="color:red;">富文本答案</span><br/>支持换行、颜色等HTML标签</p>'
  }

  // 可选:鸿蒙侧封装标题构建函数(与代码中this.TitleBuilder对应)
  @Builder
  TitleBuilder(title: string) {
    Text(title)
      .fontSize(18)
      .fontWeight(FontWeight.Bold)
      .padding(10)
  }

  build() {
    Column() {
      // 鸿蒙侧原生标题
      this.TitleBuilder('答案:')

      // 2. Web组件加载本地HTML文件
      Web({
        src: $rawfile('question.html'), // 加载rawfile目录下的question.html
        controller: this.controller     // 绑定控制器
      })
      .width('100%')
      .layoutWeight(1) // 占满剩余空间
      // 3. 关键:页面加载完成后触发(仅触发一次)
      .onPageEnd(() => {
        // 判空:确保有答案数据时才执行JS
        if (this.item.answer) {
          // 4. 执行H5页面的writeHtml函数,传递答案数据
          this.controller.runJavaScript(`writeHtml(\`${this.item.answer}\`)`)
            .then((result) => {
              // 可选:监听JS执行结果(成功/失败)
              console.log('JS函数执行结果:', result);
            })
            .catch((error) => {
              console.error('JS函数执行失败:', error);
            });
        }
      })
    }
    .width('100%')
    .height('100%')
  }
}
鸿蒙侧核心代码解析
代码片段 作用说明
WebController Web 组件的核心控制器,提供runJavaScript(执行 JS)、reload(刷新页面)、loadUrl(加载新地址)等能力
$rawfile('question.html') 加载rawfile目录下的本地 HTML 文件,相比远程 URL 更高效,无网络依赖
onPageEnd() Web 组件的页面加载完成回调(对应 H5 的window.onload),仅在页面完全加载后触发,确保 JS 函数已定义
runJavaScript() 核心 API,接收 JS 代码字符串,在 Web 组件中执行,返回 Promise 可监听执行结果
`writeHtml(\`${this.item.answer}\`) 模板字符串语法:将鸿蒙侧的this.item.answer作为参数,传递给 H5 的writeHtml函数(反斜杠是转义符,避免模板字符串嵌套冲突)

三、关键知识点与避坑指南

1. 资源路径与访问规则

  • $rawfile仅能访问rawfile目录下的文件,路径无需加/,直接写文件名(如question.html);
  • 若 HTML 需引用本地 CSS/JS 文件,需放在rawfile目录下,且路径用相对路径(如<link rel="stylesheet" href="./style.css">)。

2. JS 函数调用时机

  • 必须在onPageEnd()中调用runJavaScript,若在build()onAppear()中调用,H5 页面可能未加载完成,导致writeHtml函数未定义;
  • 若需多次执行 JS(如数据更新后),可将runJavaScript封装为方法,在数据变化时主动调用。

3. 特殊字符转义问题

当鸿蒙侧传递的this.item.answer包含单引号、双引号、反引号等特殊字符时,直接拼接会导致 JS 语法错误,需提前转义:

typescript

运行

// 封装转义函数
escapeHtml(str: string): string {
  return str.replace(/`/g, '\\`') // 转义反引号
            .replace(/'/g, '\\\'') // 转义单引号
            .replace(/"/g, '\\"'); // 转义双引号
}

// 调用时转义
const escapeAnswer = this.escapeHtml(this.item.answer);
this.controller.runJavaScript(`writeHtml(\`${escapeAnswer}\`)`);

4. 数据类型限制

  • runJavaScript传递的参数本质是字符串,若需传递对象 / 数组,需先转为 JSON 字符串:

    typescript

    运行

    // 鸿蒙侧转JSON
    const data = JSON.stringify({ answer: this.item.answer, score: 100 });
    this.controller.runJavaScript(`writeHtml(${data})`);
    
    // H5侧解析
    function writeHtml(data) {
      const { answer, score } = JSON.parse(data);
      // 渲染逻辑...
    }
    

四、扩展:H5 调用鸿蒙侧方法(双向交互)

上述示例是「鸿蒙→H5」的单向交互,若需实现「H5→鸿蒙」的反向调用(如 H5 点击按钮触发鸿蒙原生弹窗),可通过Web组件的onMessage回调实现:

1. 鸿蒙侧监听 H5 消息

typescript

运行

Web({
  src: $rawfile('question.html'),
  controller: this.controller
})
.onMessage((event: WebMessage) => {
  // 接收H5发送的消息
  const message = event.message;
  if (message.type === 'showToast') {
    // 调用鸿蒙原生弹窗
    promptAction.showToast({ message: message.content });
  }
})

2. H5 侧发送消息

javascript

运行

// H5页面中添加按钮并发送消息
<button onclick="callHarmonyOS()">触发鸿蒙弹窗</button>

<script>
  function callHarmonyOS() {
    // 通过window.harmonyOS.postMessage发送消息到鸿蒙侧
    window.harmonyOS.postMessage({
      type: 'showToast',
      content: 'H5触发的鸿蒙原生弹窗'
    });
  }
</script>

五、总结

本文基于鸿蒙Web组件实现了「鸿蒙侧调用 H5 JS 函数」的核心交互,核心要点可总结为:

  1. H5 侧:在rawfile目录下创建 HTML 文件,定义接收数据的 JS 函数(如writeHtml),做好内容渲染容器;
  2. 鸿蒙侧:通过WebController绑定Web组件,在onPageEnd回调中调用runJavaScript执行 H5 的 JS 函数,传递数据;
  3. 避坑关键:确保 JS 函数在页面加载完成后调用,处理特殊字符转义,复杂数据通过 JSON 序列化传递。

这种混合开发模式既保留了鸿蒙原生组件的交互体验,又利用了 H5 在富文本、动态排版上的优势,是鸿蒙应用开发中解决复杂内容展示的最优方案之一。在此基础上,还可扩展双向交互、JSBridge 封装等高级能力,进一步提升混合开发的效率。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐