# rich-text

组件类型:UniRichTextElement

富文本。可渲染文字样式、图片、超链接。支持部分HTML标签

# 兼容性

Web 微信小程序 Android iOS HarmonyOS
4.0 4.41 3.9 4.11 4.61

# 支持的HTML标签和属性

HTML 属性 样式
br
p text-align color background-color text-decoration
ul
li text-align color background-color text-decoration
span color background-color text-decoration
strong
i
big
small
a href
u
del
h1-h6
img src

text-decoration仅支持line-through 仅在 app-android 平台配置 mode=native 时受上述表格限制

# 属性

名称 类型 默认值 兼容性 描述
nodes any
节点列表/HTML String
selectable boolean false
文本是否可选
mode string "web"
渲染模式
合法值 兼容性 描述
web
使用webview渲染
native
使用原生渲染
space string
(string)
显示连续空格
合法值 兼容性 描述
ensp
中文字符空格一半大小
emsp
中文字符空格大小
nbsp
根据字体设置的空格大小
user-select boolean
(boolean)
文本是否可选,该属性会使节点显示为 block。已废弃,请使用 selectable
selection-handle-color string "#B4D5FE"
高亮手柄颜色
selection-background-color string "#B4D5FE"
高亮背景颜色
@itemclick (event: UniRichTextItemClickEvent) => void
内容点击事件

# 节点列表数据结构

{
    name: "p", // 标签名
    attrs: {
        style: "color: red;" // 样式
    },
    children: [ // 子节点
        {
            text: "hello uni-app x" // 文本节点
        },
        {
            name: "img", // img 标签
            attrs: {
                src: "https://web-ext-storage.dcloud.net.cn/uni-app-x/logo.ico",
                width: "100",
                height: "100"
            }
        },
        {
            name: "a", // a 标签
            attrs: {
                href: "https://www.dcloud.io"
            }
        }
    ]
}

# 事件

# UniRichTextItemClickEvent

# UniRichTextItemClickEvent 的属性值
名称 类型 必填 默认值 兼容性 描述
detail UniRichTextItemClickEventDetail
名称 类型 必备 默认值 兼容性 描述
src string <img/>图片链接
href string <a/>超链接

# 子组件

不可以嵌套组件

# 示例

示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见

扫码体验(手机浏览器跳转到App直达页)

示例

<template>
  <!-- #ifdef APP -->
  <scroll-view style="flex: 1;">
  <!-- #endif -->
		<view class="uni-padding-wrap uni-common-mt">
      <navigator url="/pages/component/rich-text/rich-text-tags" class="uni-btn-v">
        <button>rich-text渲染单个HTML标签示例</button>
      </navigator>
      <navigator url="/pages/component/rich-text/rich-text-complex" class="uni-btn-v">
        <button>rich-text渲染复杂HTML示例</button>
      </navigator>
      <navigator url="/pages/template/long-rich-text/long-rich-text" class="uni-btn-v">
        <button class="uni-btn">组件性能测试</button>
      </navigator>
			<view class="uni-title">
				<button type="default" @click="changeText">修改文本内容</button>
			</view>
			<view class="uni-title">
				<button type="default" @click="changeFontSize">切换 font-size ({{ data.currentFontSize }})</button>
			</view>
			<view class="uni-title">
				<button type="default" @click="changeLineHeight">切换 line-height ({{ data.currentLineHeight }})</button>
			</view>
			<view class="uni-title">
				<button type="default" @click="changeFontFamily">切换 font-family ({{ data.currentFontFamily }})</button>
			</view>
			<view class="text-box" id="rich-text-parent" @click="richTextParentClick">
				<rich-text id='rich-text' :style="data.richTextStyle" :nodes="data.text" mode="native">
				</rich-text>
				<view>
					<text>rich-text-parent</text>
					<text id='rich-text-str'>{{ data.richTextStr }}</text>
				</view>
			</view>
			<view class="uni-title">
				<text class="uni-subtitle-text">selectable</text>
			</view>
			<view class="text-box2">
				<rich-text style="height: 80px;" :selectable="true" :nodes="data.text"></rich-text>
			</view>
		</view>
  <!-- #ifdef APP -->
  </scroll-view style="flex: 1;">
  <!-- #endif -->
</template>

<script setup lang="uts">
	type DataType = {
		text : string;
		richTextHeight : number;
		richTextElement : UniElement | null;
		richTextStr : boolean;
		richTextStyle : string;
		currentFontSize : string;
		currentLineHeight : string;
		currentFontFamily : string;
		fontSizeIndex : number;
		lineHeightIndex : number;
		fontFamilyIndex : number;
	}
	// 定义各属性的可选值
	const fontSizeList : string[] = ["默认", "12px", "16px", "20px", "24px", "32px"]
	const lineHeightList : string[] = ["默认", "1", "1.5", "2", "2.5", "3"]
	const fontFamilyList : string[] = ["默认", "serif", "sans-serif", "monospace", "cursive"]

	// 使用reactive避免ref数据在自动化测试中无法访问
	const data = reactive({
		text: "<span>hello uni-app x!</span><br/><span>uni-app x,终极跨平台方案</span>",
		richTextHeight: 0,
		richTextElement: null,
		richTextStr: false,
		richTextStyle: "border: 1px; border-style: solid; border-color: red;",
		currentFontSize: "默认",
		currentLineHeight: "默认",
		currentFontFamily: "默认",
		fontSizeIndex: 0,
		lineHeightIndex: 0,
		fontFamilyIndex: 0
	} as DataType)

	const updateRichTextHeight = () => {
		if (data.richTextElement != null) {
			data.richTextElement!.getBoundingClientRectAsync()!.then((elRect : DOMRect) => {
				data.richTextHeight = elRect.height
				console.log('richTextHeight:', data.richTextHeight)
			})
		}
	}

	onReady(() => {

		data.richTextElement = uni.getElementById('rich-text') as UniElement
		console.log("onReady  加载完成,richTextElement= ", data.richTextElement?.tagName)
		setTimeout(() => {
			updateRichTextHeight()
		}, 2500)
	})

	const changeText = () => {
		if (data.text === "<span>hello uni-app x!</span><br/><span>uni-app x,终极跨平台方案</span>") {
			data.text = "<h1>hello uni-app x!</h1><br/><h2>uni-app x,终极跨平台方案</h2>"
		} else {
			data.text = "<span>hello uni-app x!</span><br/><span>uni-app x,终极跨平台方案</span>"
		}
    nextTick(() => {
      setTimeout(() => {
      	console.log("修改文本内容: ", data.text)

      	updateRichTextHeight()
      }, 1000)
    })
	}

	// 更新组合样式
	const updateRichTextStyle = () => {
		let style = "border: 1px; border-style: solid; border-color: red;"
		if (data.currentFontSize != "默认") {
			style += " font-size: " + data.currentFontSize + ";"
		}
		if (data.currentLineHeight != "默认") {
			style += " line-height: " + data.currentLineHeight + ";"
		}
		if (data.currentFontFamily != "默认") {
			style += " font-family: " + data.currentFontFamily + ";"
		}
		data.richTextStyle = style
		console.log("更新样式:", data.richTextStyle)
	}

	const changeFontSize = () => {
		data.fontSizeIndex = (data.fontSizeIndex + 1) % fontSizeList.length
		data.currentFontSize = fontSizeList[data.fontSizeIndex]
		console.log("切换 font-size:", data.currentFontSize)
		updateRichTextStyle()
	}

	const changeLineHeight = () => {
		data.lineHeightIndex = (data.lineHeightIndex + 1) % lineHeightList.length
		data.currentLineHeight = lineHeightList[data.lineHeightIndex]
		console.log("切换 line-height:", data.currentLineHeight)
		updateRichTextStyle()
	}

	const changeFontFamily = () => {
		data.fontFamilyIndex = (data.fontFamilyIndex + 1) % fontFamilyList.length
		data.currentFontFamily = fontFamilyList[data.fontFamilyIndex]
		console.log("切换 font-family:", data.currentFontFamily)
		updateRichTextStyle()
	}


	const getBoundingClientRectForTest = () : DOMRect => {
		return uni.getElementById('test-rich-text')?.getBoundingClientRect()!;
	}

	const richTextParentClick = () => {
		data.richTextStr = true;
	}

	const testOpenDialogPage = () => {
		uni.openDialogPage({
			url: '/pages/API/dialog-page/rich-text-in-dialog-page'
		});
	}

	const testCloseDialogPage = () => {
		uni.closeDialogPage();
	}

	defineExpose({
		data,
		changeText,
		changeFontSize,
		changeLineHeight,
		changeFontFamily,
		getBoundingClientRectForTest,
		testOpenDialogPage,
		testCloseDialogPage
	})
</script>

<style>
	.text-box {
		padding: 20px 0;
		background-color: white;
	}

	.text-box2 {
		top: 20px;
		background-color: white;
	}
</style>

# 参见

# 富文本显示的可选方案

rich-text组件是一个比较重的组件,需要注意适用场景。

  • rich-text组件适合cms系统编排的、大量使用html能力的富文本文章显示
  • rich-text不支持video组件,如果涉及video,需拆分文本内容,在video前后各放置一个rich-text组件

其他替代方案:

  • 简单的、不同风格文字排布,应该仅使用text组件,必要时也可以使用text组件嵌套text组件
  • 简单的图文混拍,用image组件+text组件拼接可以实现的,没必要使用rich-text组件
  • 自行解析node节点,动态拼接text、image、video等原生组件,也是一种方案,类似小程序领域的mp-html插件。可自行在插件市场搜索是否有这类插件
  • 原生markdown渲染:官方提供了markdown解析,动态拼接原生组件的方案,在uni-ai x开源项目中可以体验

# 调整历史

在4.7版以前,Android是原生实现rich-text,但与web规范拉齐度较低;iOS使用的是web-view;鸿蒙使用的是系统的rich-text,但该rich-text也是基于web-view实现且有细节问题。

从uni-app x4.7+,3个App平台统一使用web-view实现。鸿蒙平台直接替换了之前的实现,而Android平台则新增了mode属性配置,默认是web-view实现,但也可以通过mode=native继续使用之前的原生方式。

从5.0版本开始,鸿蒙平台蒸汽模式新增支持c语言实现的 rich-text。鸿蒙平台新增支持了 mode 属性配置,默认是 web-view 实现,可以通过设置 mode=native 使用原生方式。

# Bug & Tips

  • App-Android 平台且 mode=native 时,HTML String 类型的<img/>不支持自定义宽高,默认以 rich-text 组件宽度为基准等比缩放;节点列表类型的<img />支持自定义宽高。
  • App-Harmony 平台且 mode=native 时,暂不支持 selectable 属性。
  • 仅支持(静态、动态)设置如下style: font-size、line-height、font-family