是稻香啊头像
关注
HarmonyOS7 富文本渲染:RichText + Web 渲染 HTML 内容的正确方式封面图

HarmonyOS7 富文本渲染:RichText + Web 渲染 HTML 内容的正确方式

前言

A hand-drawn doodle illustration on pure white pap

后端扔过来一段 HTML,让我在 App 里展示。我一上来就用 Text 组件硬拼 Span,拼到第三个标签人就崩了——这得拼到猴年马月?

后来发现 HarmonyOS7 有专门的富文本渲染方案。今天聊聊两种主流方式:RichText 组件和 Web 组件,帮你根据场景选对路子。
富文本渲染是内容型 App 的刚需。新闻详情、公告说明、商品描述……后端返回的几乎都是 HTML。前端要做的事就一件:把 HTML 渲染成好看的 UI

听起来简单,但坑不少:标签支持不全、图片点击没反应、样式跟原生不一致……选错方案,后面全是补丁。

富文本需求场景

不同场景对富文本的要求差异很大:

场景HTML 复杂度交互需求推荐方案
用户协议 / 隐私政策简单(p/a/b 标签为主)RichText
新闻详情中等(图文混排)图片点击放大RichText

A hand-drawn doodle illustration on pure white pap

| 活动页 / 营销页 | 复杂(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%')
  }
}

A hand-drawn doodle illustration on pure white pap

关键代码讲解:

  • 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 依赖 localStorage
  • loadData() —— 加载 HTML 字符串,三个参数分别是内容、MIME 类型、编码
  • onMessage() —— 接收 HTML 里 window.postMessage() 发送的消息,这是 Web 和原生通信的桥梁
  • onPageEnd() —— 页面加载完成时触发,在这里注入 HTML 内容比较稳妥

Web 组件嵌套在 Scroll 里时,别忘了加 .nestedScroll() 处理滚动冲突。

两种方案对比

维度RichTextWeb
渲染性能高(原生渲染)低(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

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--