前言

后端扔过来一段 HTML,让我在 App 里展示。我一上来就用 Text 组件硬拼 Span,拼到第三个标签人就崩了——这得拼到猴年马月?
后来发现 HarmonyOS7 有专门的富文本渲染方案。今天聊聊两种主流方式:RichText 组件和 Web 组件,帮你根据场景选对路子。
富文本渲染是内容型 App 的刚需。新闻详情、公告说明、商品描述……后端返回的几乎都是 HTML。前端要做的事就一件:把 HTML 渲染成好看的 UI。
听起来简单,但坑不少:标签支持不全、图片点击没反应、样式跟原生不一致……选错方案,后面全是补丁。
富文本需求场景
不同场景对富文本的要求差异很大:
| 场景 | HTML 复杂度 | 交互需求 | 推荐方案 |
|---|---|---|---|
| 用户协议 / 隐私政策 | 简单(p/a/b 标签为主) | 无 | RichText |
| 新闻详情 | 中等(图文混排) | 图片点击放大 | RichText |

| 活动页 / 营销页 | 复杂(CSS 动画+JS 交互) | 高 | Web |
| 第三方网页嵌入 | 不可控 | 全交互 | Web |
简单总结:内容为主用 RichText,交互为主用 Web。
RichText 组件
RichText 是 HarmonyOS7 专门为 HTML 内容渲染设计的组件,用法简单粗暴——直接把 HTML 字符串塞进去:
@Entry
@Component
struct RichTextDemo {
private htmlContent: string = `
<h2>HarmonyOS7 更新公告</h2>
<p>本次更新带来了<strong>全新的 ArkUI 组件</strong>,性能提升显著。</p>
<ul>
<li>新增 Flex 弹性布局组件</li>
<li>优化 List 滚动性能</li>
<li>修复已知 <em>50+</em> 问题</li>
</ul>
<p>详细内容请访问<a href="https://developer.huawei.com">开发者官网</a>。</p>
`
build() {
Scroll() {
Column() {
RichText(this.htmlContent)
.width('100%')
.padding(16)
.onReady(() => {
console.info('RichText 渲染完成')
})
}
}
.width('100%')
.height('100%')
}
}

关键代码讲解:
RichText(this.htmlContent)—— 直接传入 HTML 字符串,组件自动解析渲染.onReady()—— 渲染完成的回调,可以在这里做后续处理(比如图片加载后的高度调整)- RichText 只支持通用属性中的 width、height、size、layoutWeight,不能设 fontSize、fontColor 这些文本属性——因为样式由 HTML 标签控制
RichText 的样式完全由 HTML 内联决定,想改字号得在 HTML 里写
<span style="font-size:18px">。
支持的 HTML 标签
RichText 不是啥 HTML 标签都支持,以下是常用标签的支持情况:
| 标签 | 说明 | 示例 |
|---|---|---|
<h1>~<h6> | 标题 | <h2>标题</h2> |
<p> | 段落 | <p>内容</p> |
<a> | 超链接 | <a href="url">链接</a> |
<strong> / <b> | 加粗 | <b>加粗</b> |
<em> / <i> | 斜体 | <i>斜体</i> |
<u> | 下划线 | <u>下划线</u> |
<s> | 删除线 | <s>删除</s> |
<ul> / <ol> | 列表 | <ul><li>项</li></ul> |
<img> | 图片 | <img src="url"> |
<table> | 表格 | <table><tr><td>...</td></tr></table> |
<div> / <span> | 容器 | <div style="...">...</div> |
<br> | 换行 | <br> |
<hr> | 分割线 | <hr> |
不支持的标签会被直接忽略,不会报错也不会显示。所以用之前先确认你的 HTML 里有没有奇奇怪怪的标签。
Web 渲染复杂 HTML
当 HTML 包含复杂 CSS、JavaScript 或者 RichText 不支持的标签时,就得用 Web 组件了:
import webview from '@ohos.web.webview'
@Entry
@Component
struct WebRichTextDemo {
private webController: webview.WebviewController = new webview.WebviewController()
private htmlContent: string = `
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body { margin: 0; padding: 16px; font-family: sans-serif; color: #333; }
h2 { color: #007DFF; }
.highlight { background: linear-gradient(120deg, #f6d365 0%, #fda085 100%);
padding: 4px 8px; border-radius: 4px; }
.card { background: #f8f8f8; border-radius: 12px; padding: 16px; margin: 12px 0; }
img { max-width: 100%; border-radius: 8px; }
</style>
</head>
<body>
<h2>限时活动</h2>
<div class="card">
<p>活动期间,<span class="highlight">全场商品8折</span>!</p>
<img src="https://example.com/banner.jpg" onclick="onImageClick(this.src)">
</div>
<script>
function onImageClick(src) {
window.postMessage(JSON.stringify({type:'imageClick', src: src}));
}
</script>
</body>
</html>
`
build() {
Column() {
Web({ src: '', controller: this.webController })
.width('100%')
.layoutWeight(1)
.javaScriptAccess(true)
.domStorageAccess(true)
.onPageEnd(() => {
this.webController.loadData(
this.htmlContent,
'text/html',
'UTF-8'
)
})
.onMessage((event) => {
let data = JSON.parse(event.data as string)
if (data.type === 'imageClick') {
console.info(`图片被点击: ${data.src}`)
}
})
}
.width('100%')
.height('100%')
}
}
关键代码讲解:
javaScriptAccess(true)—— 必须开启,不然<script>里的代码不执行domStorageAccess(true)—— 开启 DOM 存储,某些 HTML 依赖 localStorageloadData()—— 加载 HTML 字符串,三个参数分别是内容、MIME 类型、编码onMessage()—— 接收 HTML 里window.postMessage()发送的消息,这是 Web 和原生通信的桥梁onPageEnd()—— 页面加载完成时触发,在这里注入 HTML 内容比较稳妥
Web 组件嵌套在 Scroll 里时,别忘了加
.nestedScroll()处理滚动冲突。
两种方案对比
| 维度 | RichText | Web |
|---|---|---|
| 渲染性能 | 高(原生渲染) | 低(WebView 引擎) |
| HTML 支持度 | 有限(基础标签) | 完整(含 CSS/JS) |
| 交互能力 | 仅链接点击 | 完整 JS 交互 |
| 内存占用 | 低 | 高 |
| 样式控制 | 受限(只支持4个通用属性) | 灵活(CSS 全支持) |
| 与原生通信 | onReady 回调 | postMessage 双向通信 |
| 加载速度 | 快 | 慢(需初始化引擎) |
图片点击处理
RichText 里的图片点击是个常见需求,可惜 RichText 本身没有直接提供图片点击回调。变通方案:
方案一:用 onReady + 正则替换
build() {
RichText(this.processHtml(this.htmlContent))
.width('100%')
.padding(16)
}
processHtml(html: string): string {
return html.replace(
/<img\s+src="([^"]*)"/g,
'<img src="$1" onclick="window.open(\'$1\')"'
)
}
方案二:直接用 Web 组件
如果图片点击交互比较复杂(比如要弹出预览、左右滑动),老老实实用 Web + postMessage,别折腾了。
写在最后
选方案的核心判断:HTML 有没有 CSS 动画或 JS 交互?
- 没有 → RichText,轻快省
- 有 → Web,别犹豫
别想着用 RichText 硬撑复杂 HTML,后期补丁比重写还痛苦。也别啥都用 Web,一个简单的用户协议页加个 WebView,内存占用直接翻倍。
选对工具,事半功倍。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/qq_37048082/article/details/162969659




