HarmonyOS ArkTS 与 H5 混合开发:Web 组件调用 JS 函数全解析
首先在鸿蒙项目中创建本地 HTML 文件,定义接收鸿蒙数据并渲染内容的 JS 函数,这是交互的基础。本文基于鸿蒙WebH5 侧:在rawfile目录下创建 HTML 文件,定义接收数据的 JS 函数(如writeHtml),做好内容渲染容器;鸿蒙侧:通过绑定Web组件,在onPageEnd回调中调用执行 H5 的 JS 函数,传递数据;避坑关键:确保 JS 函数在页面加载完成后调用,处理特殊字符转
在 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 函数」的核心交互,核心要点可总结为:
- H5 侧:在
rawfile目录下创建 HTML 文件,定义接收数据的 JS 函数(如writeHtml),做好内容渲染容器; - 鸿蒙侧:通过
WebController绑定Web组件,在onPageEnd回调中调用runJavaScript执行 H5 的 JS 函数,传递数据; - 避坑关键:确保 JS 函数在页面加载完成后调用,处理特殊字符转义,复杂数据通过 JSON 序列化传递。
这种混合开发模式既保留了鸿蒙原生组件的交互体验,又利用了 H5 在富文本、动态排版上的优势,是鸿蒙应用开发中解决复杂内容展示的最优方案之一。在此基础上,还可扩展双向交互、JSBridge 封装等高级能力,进一步提升混合开发的效率。
更多推荐
所有评论(0)