RichEditor 富文本实操:图文混排、超链接、自定义样式控制

0 阅读3分钟

一、前言

在很多业务场景里,我们都需要富文本编辑能力:公告编辑、工单备注、内容发帖、文档草稿等。ArkUI 提供的 RichEditor 组件,是官方原生富文本控件,不用额外引入第三方 Web 富文本,能直接在页面内完成文字编辑、插入图片、添加链接、修改文字样式。

不少同学初次上手 RichEditor,容易踩坑:图片插入后布局错乱、超链接点击不生效、样式修改只选中部分文字不生效、数据回显丢失格式。这些问题大多是对组件数据模型、编辑范围接口不熟悉导致。本文基于最新鸿蒙 API,讲解 RichEditor 核心用法,附带可直接运行完整代码。

二、RichEditor 基础概念

RichEditor 的内容由RichEditorSpan构成,一段富文本可以包含文本、图片、链接等不同类型的 Span。

  • TextSpan:普通文本片段,控制字体、颜色、字号、粗斜体
  • ImageSpan:图片片段,承载图文混排能力
  • UrlSpan:超链接片段,可绑定跳转地址

所有的样式操作,都要先获取当前光标选中范围TextRange,再针对选中区域追加或者修改 Span 属性。RichEditor 本身是可编辑组件,用户可以直接在界面上输入、选中文字。

三、基础页面搭建

先搭建基础页面,放置 RichEditor 与一组操作按钮,用来切换样式、插入图片、添加链接。

@Entry
@Component
struct RichEditorDemo {
  @State richController: RichEditorController = new RichEditorController()
  @State content: RichEditorSpan[] = [
    new RichEditorTextSpan("欢迎使用RichEditor富文本编辑器\n", {fontSize: 18, fontColor: "#222222", fontWeight: FontWeight.Bold}),
    new RichEditorTextSpan("原生组件实现图文混排、超链接与自定义样式\n", {fontSize: 14, fontColor: "#666666"})
  ]

  build() {
    Column() {
      // 操作工具栏
      Row() {
        Button("加粗").onClick(() => this.setBold())
        Button("变色").onClick(() => this.setTextColor())
        Button("插入图片").onClick(() => this.insertImage())
        Button("添加链接").onClick(() => this.insertUrl())
      }
      .width("100%")
      .margin({bottom: 12})
      .justifyContent(FlexAlign.SpaceAround)

      RichEditor(this.content, this.richController)
        .width("100%")
        .height(400)
        .border({width:1, color:"#eeeeee"})
        .placeholder("请输入富文本内容...")
    }
    .padding(16)
    .width("100%")
  }

1. 文字加粗实现

获取当前选中区域,新建文本 Span 覆盖选中范围,设置 fontWeight。

  setBold() {
    const range: TextRange = this.richController.getCaretOffset()
    if (range.start === range.end) return
    const selectSpans = this.richController.getSpansByRange(range)
    selectSpans.forEach(span => {
      if (span instanceof RichEditorTextSpan) {
        span.fontWeight = FontWeight.Bold
      }
    })
  }

2. 修改文字颜色

  setTextColor() {
    const range: TextRange = this.richController.getCaretOffset()
    if (range.start === range.end) return
    const spans = this.richController.getSpansByRange(range)
    spans.forEach(span => {
      if (span instanceof RichEditorTextSpan) {
        span.fontColor = "#0066FF"
      }
    })
  }

3. 插入图片,图文混排

示例使用资源目录图片,替换成沙箱文件路径即可实现拍照 / 相册图片插入。

  insertImage() {
    const caretPos = this.richController.getCaretOffset().start
    const imgSpan = new RichEditorImageSpan($r("sys.media.ohos_ic_public_photo"), {
      imageWidth: 200,
      imageHeight: 140
    })
    this.richController.insertSpan(caretPos, imgSpan)
  }

4. 插入超链接

  insertUrl() {
    const range: TextRange = this.richController.getCaretOffset()
    if (range.start === range.end) return
    const urlSpan = new RichEditorUrlSpan("点击访问官网", "https://www.harmonyos.com", {
      fontColor: "#0066FF",
      textDecoration: TextDecoration.Underline
    })
    this.richController.replaceSpan(range, urlSpan)
  }
}

四、富文本序列化与回显

实际业务中,需要把富文本内容保存、页面刷新后重新渲染。RichEditorSpan 数组可以直接转为 JSON 存储,读取后还原 Span 数组。

// 导出富文本内容,保存到持久化存储
saveRichContent() {
  const dataStr = JSON.stringify(this.content)
  // 这里可以写入Preferences/RDB
  console.info("富文本数据", dataStr)
}

// 读取JSON,回显富文本
restoreRichContent(jsonStr: string) {
  const rawData = JSON.parse(jsonStr)
  this.content = rawData.map((item: Record<string,any>) => {
    if(item.type === "text"){
      return new RichEditorTextSpan(item.text, item.style)
    }else if(item.type === "image"){
      return new RichEditorImageSpan(item.imageValue, item.style)
    }else if(item.type === "url"){
      return new RichEditorUrlSpan(item.text, item.url, item.style)
    }
  })
}

五、小结

RichEditor 原生富文本组件,省去 WebView 方案带来的包体积、通信调试成本。核心思路就是通过RichEditorController获取光标选区,增改 TextSpan、ImageSpan、UrlSpan 实现图文、链接、自定义样式。 基础的编辑、内容导出、回显逻辑可以直接复用上面代码,在此基础