当前位置: 首页 > news >正文

ReactNative项目OpenHarmony三方库集成实战:react-native-render-html

欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net

项目基于 RN 0.72.90 开发

📋 前言

在移动应用开发中,HTML 内容渲染是一项常见需求,特别是在新闻资讯、富文本编辑、邮件展示等场景中。React Native 原生并不支持直接渲染 HTML,而react-native-render-html是一个功能强大的 HTML 渲染库,能够将 HTML 内容转换为 React Native 组件,支持丰富的样式定制、图片处理等特性,是处理富文本内容的理想选择。

🎯 库简介

基本信息

为什么需要 HTML 渲染库?

特性WebView 方案react-native-render-html
性能⚠️ 较重✅ 轻量级原生组件
样式定制⚠️ 受限✅ 完全可控
原生交互⚠️ 复杂✅ 直接使用 RN 组件
内存占用⚠️ 较高✅ 低内存占用
HarmonyOS 支持⚠️ 需适配✅ 完善适配

核心功能

功能说明HarmonyOS 支持
sourceHTML 内容源
contentWidth内容宽度
baseStyle基础样式
tagsStyles标签样式
classesStyles类名样式
ignoredDomTags忽略的标签
allowedStyles允许的样式属性
enableCSSInlineProcessing内联 CSS 处理
onHTMLLoadedHTML 加载完成回调

兼容性验证

在以下环境验证通过:

📦 安装步骤

1. 安装依赖

# RN 0.72/0.77 版本npminstallreact-native-render-html@6.3.4# 或者使用 yarnyarnaddreact-native-render-html@6.3.4

2. 验证安装

安装完成后,检查package.json文件:

{"dependencies":{"react-native-render-html":"^6.3.4"}}

🔧 HarmonyOS 平台配置

本库为纯 JavaScript 实现,无需额外的原生端配置。安装完成后即可直接使用。

📖 API 详解

source - HTML 内容源

指定要渲染的 HTML 内容,支持多种格式。

类型HTMLSource

必填:是

HTMLSource 结构

属性类型说明
htmlstringHTML 字符串
uristring远程 HTML 地址
domDOMDOM 对象

使用场景

const source = { html: ` <h1>标题示例</h1> <p>这是一段<strong>加粗</strong>的文本内容。</p> <ul> <li>列表项 1</li> <li>列表项 2</li> </ul> `, }; <RenderHtml contentWidth={width} source={source} />

contentWidth - 内容宽度

设置 HTML 内容的渲染宽度,通常使用屏幕宽度减去边距。

类型number

必填:否(但强烈建议设置)

使用场景

const { width } = useWindowDimensions(); <RenderHtml contentWidth={width - 32} source={{ html: "<p>内容宽度自适应示例</p>" }} />

baseStyle - 基础样式

为整个 HTML 文档设置默认样式,可继承的样式会传递给子元素。

类型MixedStyleDeclaration

使用场景

const baseStyle = { fontSize: 16, color: "#333333", lineHeight: 24, fontFamily: "System", }; <RenderHtml contentWidth={width} source={source} baseStyle={baseStyle} />

tagsStyles - 标签样式

为特定 HTML 标签设置样式。

类型Record<string, MixedStyleDeclaration>

使用场景

const tagsStyles = { h1: { fontSize: 28, fontWeight: "700" as const, color: "#1a1a1a", marginBottom: 16, }, h2: { fontSize: 22, fontWeight: "600" as const, color: "#333333", marginBottom: 12, }, p: { fontSize: 16, lineHeight: 24, color: "#666666", marginBottom: 12, }, blockquote: { borderLeftWidth: 4, borderLeftColor: "#007AFF", paddingLeft: 16, marginVertical: 12, backgroundColor: "#F5F5F5", paddingVertical: 8, }, }; <RenderHtml contentWidth={width} source={source} tagsStyles={tagsStyles} />

classesStyles - 类名样式

为 CSS 类名设置样式。

类型Record<string, MixedStyleDeclaration>

使用场景

const source = { html: ` <p class="highlight">高亮文本示例</p> <p class="warning">警告文本示例</p> <p class="success">成功文本示例</p> `, }; const classesStyles = { highlight: { backgroundColor: "#FFF3CD", padding: 8, borderRadius: 4, borderLeftWidth: 4, borderLeftColor: "#FFC107", }, warning: { backgroundColor: "#F8D7DA", padding: 8, borderRadius: 4, borderLeftWidth: 4, borderLeftColor: "#DC3545", color: "#721C24", }, success: { backgroundColor: "#D4EDDA", padding: 8, borderRadius: 4, borderLeftWidth: 4, borderLeftColor: "#28A745", color: "#155724", }, }; <RenderHtml contentWidth={width} source={source} classesStyles={classesStyles} />

ignoredDomTags - 忽略标签

指定要忽略的 HTML 标签列表。

类型string[]

使用场景

<RenderHtml contentWidth={width} source={source} ignoredDomTags={["script", "style", "iframe"]} />

onHTMLLoaded - HTML 加载回调

HTML 内容加载完成时触发的回调函数。

类型(html: string) => void

使用场景

const handleHTMLLoaded = (html: string) => { console.log("HTML 加载完成:", html.length, "字符"); }; <RenderHtml contentWidth={width} source={source} onHTMLLoaded={handleHTMLLoaded} />

📋 完整示例

importReact,{useState}from"react";import{View,Text,StyleSheet,ScrollView,TouchableOpacity,useWindowDimensions,SafeAreaView,StatusBar,TextInput,}from"react-native";importRenderHtmlfrom"react-native-render-html";typeExampleType="basic"|"styled"|"news";constHTML_EXAMPLES:Record<ExampleType,string>={basic:`<h1>基础 HTML 渲染</h1> <p>这是一个基础的 HTML 渲染示例,展示了常见的 HTML 元素。</p> <h2>文本格式</h2> <p>支持<strong>加粗</strong>、<em>斜体</em>、<u>下划线</u>等格式。</p> <p>也支持<code>代码片段</code>和<mark>高亮文本</mark>。</p> <h2>列表</h2> <ul> <li>无序列表项 1</li> <li>无序列表项 2</li> <li>无序列表项 3</li> </ul> <ol> <li>有序列表项 1</li> <li>有序列表项 2</li> <li>有序列表项 3</li> </ol> <h2>引用</h2> <blockquote> 这是一段引用文本,通常用于展示他人的言论或重要内容。 </blockquote>`,styled:`<h1 class="title">样式化内容</h1> <p class="intro">通过自定义样式,可以实现丰富的视觉效果。</p> <div class="card"> <h3>卡片标题</h3> <p>这是一个带有自定义样式的卡片组件。</p> </div> <div class="alert warning"> <strong>警告:</strong>这是一条警告信息。 </div> <div class="alert success"> <strong>成功:</strong>操作已成功完成。 </div> <div class="alert info"> <strong>提示:</strong>这是一条提示信息。 </div>`,news:`<article> <h1>React Native 鸿蒙适配取得重大进展</h1> <p class="meta">发布时间:2024年1月15日 | 作者:技术团队</p> <p>近日,React Native 鸿蒙适配工作取得了重大进展。开发团队成功适配了多个核心组件和第三方库,为开发者提供了更完善的跨平台开发体验。</p> <h2>主要更新</h2> <ul> <li>新增 50+ 三方库适配支持</li> <li>优化了渲染性能,提升 30%</li> <li>完善了开发文档和示例代码</li> <li>修复了若干已知问题</li> </ul> <blockquote> "这次更新标志着 React Native 在鸿蒙平台上的成熟度达到了新的高度。" —— 项目负责人 </blockquote> <h2>后续计划</h2> <p>团队将继续推进适配工作,预计在下一版本中支持更多常用库,并进一步优化性能表现。</p> </article>`,};constApp:React.FC=()=>{const{width}=useWindowDimensions();const[activeExample,setActiveExample]=useState<ExampleType>("basic");const[customHtml,setCustomHtml]=useState("<p>输入 HTML 内容测试</p>");const[showCustomInput,setShowCustomInput]=useState(false);constbaseStyle={fontSize:16,color:"#333333",lineHeight:26,};consttagsStyles={h1:{fontSize:28,fontWeight:"700"asconst,color:"#1a1a1a",marginBottom:16,marginTop:8,},h2:{fontSize:22,fontWeight:"600"asconst,color:"#333333",marginBottom:12,marginTop:16,},h3:{fontSize:18,fontWeight:"600"asconst,color:"#444444",marginBottom:8,},p:{fontSize:16,lineHeight:26,color:"#333333",marginBottom:12,},ul:{marginBottom:16,},ol:{marginBottom:16,},li:{fontSize:16,lineHeight:24,marginBottom:4,},blockquote:{borderLeftWidth:4,borderLeftColor:"#007AFF",paddingLeft:16,marginVertical:16,backgroundColor:"#F5F5F5",paddingVertical:12,paddingRight:16,borderRadius:4,},code:{backgroundColor:"#F0F0F0",paddingHorizontal:8,paddingVertical:2,borderRadius:4,fontFamily:"monospace",},article:{paddingBottom:20,},};constclassesStyles={title:{fontSize:32,fontWeight:"700"asconst,textAlign:"center"asconst,color:"#007AFF",marginBottom:20,},intro:{fontSize:18,color:"#666666",textAlign:"center"asconst,marginBottom:24,},card:{backgroundColor:"#FFFFFF",borderRadius:12,padding:20,marginVertical:12,shadowColor:"#000",shadowOffset:{width:0,height:2},shadowOpacity:0.1,shadowRadius:8,elevation:3,},alert:{padding:16,borderRadius:8,marginVertical:8,},warning:{backgroundColor:"#FFF3CD",borderLeftWidth:4,borderLeftColor:"#FFC107",},success:{backgroundColor:"#D4EDDA",borderLeftWidth:4,borderLeftColor:"#28A745",},info:{backgroundColor:"#D1ECF1",borderLeftWidth:4,borderLeftColor:"#17A2B8",},meta:{fontSize:14,color:"#999999",marginBottom:16,},};constrenderExampleButton=(type:ExampleType,label:string)=>(<TouchableOpacity key={type}style={[styles.exampleButton,activeExample===type&&styles.exampleButtonActive,]}onPress={()=>{setActiveExample(type);setShowCustomInput(false);}}><Text style={[styles.exampleButtonText,activeExample===type&&styles.exampleButtonTextActive,]}>{label}</Text></TouchableOpacity>);return(<SafeAreaView style={styles.container}><StatusBar barStyle="dark-content"backgroundColor="#FFFFFF"/><View style={styles.header}><Text style={styles.headerTitle}>HTML渲染示例</Text><TouchableOpacity style={styles.customButtonHeader}onPress={()=>setShowCustomInput(!showCustomInput)}><Text style={styles.customButtonHeaderText}>{showCustomInput?"预设示例":"自定义"}</Text></TouchableOpacity></View>{!showCustomInput&&(<View style={styles.tabBar}>{renderExampleButton("basic","基础")}{renderExampleButton("styled","样式")}{renderExampleButton("news","新闻")}</View>)}{showCustomInput?(<View style={styles.customInputContainer}><TextInput style={styles.htmlInput}value={customHtml}onChangeText={setCustomHtml}multiline placeholder="输入 HTML 内容"textAlignVertical="top"/><ScrollView style={styles.previewContainer}><RenderHtml contentWidth={width-32}source={{html:customHtml}}baseStyle={baseStyle}tagsStyles={tagsStyles}/></ScrollView></View>):(<ScrollView style={styles.content}><View style={styles.htmlContainer}><RenderHtml contentWidth={width-32}source={{html:HTML_EXAMPLES[activeExample]}}baseStyle={baseStyle}tagsStyles={tagsStyles}classesStyles={classesStyles}/></View></ScrollView>)}</SafeAreaView>);};conststyles=StyleSheet.create({container:{flex:1,backgroundColor:"#F5F5F5",},header:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",padding:16,backgroundColor:"#FFFFFF",borderBottomWidth:1,borderBottomColor:"#E5E5EA",},headerTitle:{fontSize:20,fontWeight:"700",color:"#333333",},customButtonHeader:{backgroundColor:"#007AFF",paddingHorizontal:16,paddingVertical:8,borderRadius:8,},customButtonHeaderText:{color:"#FFFFFF",fontSize:14,fontWeight:"600",},tabBar:{flexDirection:"row",backgroundColor:"#FFFFFF",paddingHorizontal:16,paddingVertical:12,gap:8,},exampleButton:{paddingHorizontal:16,paddingVertical:8,backgroundColor:"#F0F0F0",borderRadius:20,},exampleButtonActive:{backgroundColor:"#007AFF",},exampleButtonText:{fontSize:14,color:"#666666",fontWeight:"500",},exampleButtonTextActive:{color:"#FFFFFF",},content:{flex:1,},htmlContainer:{backgroundColor:"#FFFFFF",margin:16,padding:16,borderRadius:12,minHeight:400,},customInputContainer:{flex:1,padding:16,},htmlInput:{backgroundColor:"#FFFFFF",borderRadius:8,padding:12,fontSize:14,fontFamily:"monospace",height:150,marginBottom:16,borderWidth:1,borderColor:"#E5E5EA",},previewContainer:{flex:1,backgroundColor:"#FFFFFF",borderRadius:8,padding:16,},});exportdefaultApp;

⚠️ 注意事项

部分标签可能并不能适配。

遗留问题

使用建议

  1. 设置 contentWidth: 始终设置contentWidth属性以确保正确的布局计算
  2. 使用 useWindowDimensions: 结合useWindowDimensions()实现响应式布局
  3. 性能优化: 对于长内容,考虑分块渲染或虚拟列表

常见问题

Q: 图片不显示?

A: 确保图片 URL 可访问,并且有正确的网络权限。远程图片需要配置网络请求。

Q: 样式不生效?

A: 检查样式属性名称是否正确,React Native 样式属性与 CSS 有所不同。例如使用backgroundColor而不是background-color

Q: HTML 内容过长导致卡顿?

A: 考虑分块渲染或使用虚拟列表优化性能。

Q: 特殊字符显示异常?

A: 确保 HTML 内容正确编码,必要时使用实体字符。

http://www.jsqmd.com/news/579150/

相关文章:

  • OpenClaw+Qwen2.5-VL-7B:3种方法提升图文任务成功率
  • 星图平台快速体验:OpenClaw镜像+Qwen3.5-9B完成图片分析沙盒测试
  • 嵌入式开发中的位操作技巧与实战应用
  • 关于eclipse2019中导入克隆的web项目
  • OpenClaw+Qwen3.5-9B办公自动化:3类图片处理场景实测
  • Spring IoC 与 DI 核心详解 —— 基于 XML 配置:Bean 创建、依赖注入与生命周期全解析(Spring系列1)
  • Sodaq_LSM303AGR库深度解析:六轴IMU嵌入式驱动设计与低功耗实践
  • 美胸-年美-造相Z-Turbo案例分享:从简单描述到精美成图的全过程展示
  • 3 个高级思路,让你的 AI 绘画 / 视频从此充满想象力
  • 新手福音:用快马平台理解openclaw架构图并生成你的第一个应用
  • 初识Maven
  • 2026年矿山煤矿电力电缆生产厂家推荐:中低压、低压、中压、变频等电缆厂家 - 品牌2026
  • OpenClaw+百川2-13B-4bits量化模型:个人周报自动化生成与整理方案
  • 阿里云百炼 Coding Plan 售罄、Lite 停售、Pro 抢不到?最新解决方案
  • OpenClaw飞书机器人配置:Qwen3.5-9B-AWQ-4bit对话触发全流程
  • Diablo Edit2实战解决方案:从存档修复到角色定制的完整指南
  • 2026年国内阻燃防火电缆推荐!阻燃防火电缆国内一线品牌精选 - 品牌2026
  • “title“: “从Java全栈开发视角看现代Web应用架构设计“,
  • 什么是Token?一文读懂Token是什么,影响你的使用成本!
  • TI SAR ADC模型(Matlab) 包含各类非理想因素,时钟偏差,增益偏差
  • Swift学习笔记13-可选链
  • 从手动挡到自动驾驶:Infoseek如何用工程思维重构媒体发布
  • OpenClaw镜像体验报告:千问3.5-35B-A3B-FP8多模态任务云端实测
  • 状态机中的人物状态
  • 50万行代码泄露后,开发者们凌晨4点冲进Rust:这次真的撕开了
  • OpenClaw备份与迁移:Qwen2.5-VL-7B配置快速转移指南
  • 2026年最吃香的IT岗!AI大模型应用开发,普通人如何逆袭百万年薪?
  • 工业冷水机控制程序西门子1200plc含压缩机,电子膨胀阀控制策略,饱和温度计算公式
  • PCB Layout设计核心要点与工程实践
  • 智能家庭教育:OpenClaw+Phi-3-vision-128k-instruct批改孩子手写作业