富文本编辑器,支持内容输入、格式调整和状态管理,方便构建可定制的编辑与信息录入界面。
Access rate limit exceeded. Please log in to continue.
react-native-pell-rich-editor
本项目基于 wxik/react-native-rich-editor 开发,并适配 React Native for OpenHarmony。 如果在使用过程中有任何问题,可以在 GitCode 提交 Issue,我们会及时跟进。
项目介绍
@hxa-rn/react-native-pell-rich-editor 是一个 React Native 富文本编辑器,支持编辑 HTML 内容,并通过工具栏提供常用的文本格式化功能。本仓库在保留原始 React Native 实现的基础上新增 HarmonyOS(OpenHarmony)适配,HarmonyOS 端使用 ArkWeb 承载富文本编辑页面,并通过 React Native Fabric 组件完成 JavaScript 与原生侧通信。
- 富文本编辑:编辑器页面基于
contenteditable实现,文本输入、粘贴、按键与光标变化通过回调输出到 JavaScript 侧。 - 格式化工具栏:
RichToolbar提供加粗、斜体、下划线、标题、列表、对齐、引用、代码块等操作,并支持自定义图标、自定义渲染与自定义操作集合。 - 内容读写:
setContentHTML设置编辑器 HTML,onChange与getContentHtml读取当前 HTML。 - 富媒体与链接:
insertImage、insertVideo、insertLink插入远程图片、视频和超链接。 - 撤销与重做:通过
actions.undo、actions.redo触发编辑器历史操作。 - 自定义脚本:
command、commandDOM、injectJavascript向编辑器页面注入脚本执行自定义逻辑。 - HarmonyOS 适配:原生侧以 HAR 模块提供,使用 ArkWeb 承载编辑页面,并通过 Fabric 组件与 JavaScript 侧通信。
集成指南
安装
在 React Native 工程根目录执行:
npm install @hxa-rn/react-native-pell-rich-editor
需要宿主工程提供 react-native(>=0.72)。
Autolinking
本包已配置 React Native for OpenHarmony Autolinking,安装依赖后由宿主工程自动接入,无需手动注册。
导入
import {
RichEditor,
RichToolbar,
actions,
defaultActions,
createHTML,
getContentCSS,
} from '@hxa-rn/react-native-pell-rich-editor';
使用说明
基础用法
import React, {useRef} from 'react';
import {RichEditor, RichToolbar, actions} from '@hxa-rn/react-native-pell-rich-editor';
export default function EditorScreen(): JSX.Element {
const editorRef = useRef<RichEditor>(null);
return (
<>
<RichEditor
ref={editorRef}
initialContentHTML="<p>Hello HarmonyOS</p>"
placeholder="在这里输入富文本内容"
initialHeight={180}
editorStyle={{backgroundColor: '#ffffff', color: '#18202b', placeholderColor: '#8d99a8'}}
onChange={(value: string) => console.log(value)}
onHeightChange={(value: number) => console.log(value)}
onLink={(url: string) => console.log(url)}
onCursorPosition={(y: number) => console.log('光标所在行的 y', y)}
onCursorRect={(rect: {x: number; y: number; width: number; height: number}) =>
console.log('光标矩形', rect)
}
/>
<RichToolbar
editor={editorRef}
actions={[
actions.setBold,
actions.setItalic,
actions.setUnderline,
actions.heading1,
actions.insertBulletsList,
actions.undo,
actions.redo,
]}
selectedIconTint="#2878f0"
/>
</>
);
}
RichToolbar 通过 editor 属性持有 RichEditor 的 ref,未传 actions 时使用默认操作集合 defaultActions。onChange 在内容变化时返回当前 HTML;getContentHtml 在类型定义中已标记为 @deprecated,新代码建议使用 onChange。onHeightChange 返回内容实际高度,通常用它驱动编辑器容器高度。editorStyle 用于设置编辑器背景色、文字色、光标色与占位符颜色,HarmonyOS 端由 ArkWeb 页面渲染。
通过 Ref 操作编辑器内容
const editorRef = useRef<RichEditor>(null);
// 在光标位置插入文本或 HTML
editorRef.current?.insertText('HarmonyOS');
editorRef.current?.insertHTML('<blockquote>引用内容</blockquote>');
// 插入远程图片与视频,第二个参数为内联样式
editorRef.current?.insertImage('https://picsum.photos/480/240', 'max-width:98%;display:block;margin:8px auto;');
editorRef.current?.insertVideo('https://media.w3.org/2010/05/sintel/trailer.mp4', 'width:100%;');
// 设置选中文本的格式
editorRef.current?.preCode('javascript');
editorRef.current?.setFontSize('4'); // 1–7(4 ≈ 18px)
editorRef.current?.setFontName('serif');
editorRef.current?.setForeColor('#d4380d');
editorRef.current?.setHiliteColor('#fff566');
// 焦点与键盘
editorRef.current?.focusContentEditor();
editorRef.current?.blurContentEditor();
editorRef.current?.dismissKeyboard();
setFontSize 的取值是浏览器字号 1–7(分别为 10px、13px、16px、18px、24px、32px、48px),只接受 1–7:底层走的是 document.execCommand('fontSize'),传 CSS 长度(如 '18px')会被浏览器忽略、表现为"点了没变化"。insertImage、insertVideo 的第一个参数为资源地址,远程资源依赖网络连通性。
接口文档
以下 API 依据入口文件 src/index.js 的导出,以及 src/RichEditor.js、src/RichToolbar.js 中的属性默认值和 JSDoc 整理。
RichEditor
富文本编辑器组件,HarmonyOS 端基于 ArkWeb 承载编辑页面。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
html |
string |
未声明 | 直接设置编辑器 HTML。 |
initialContentHTML |
string |
'' |
编辑器初始化内容。 |
placeholder |
string |
'' |
空内容时的占位文本。 |
disabled |
boolean |
false |
是否禁止编辑。 |
useContainer |
boolean |
true |
是否将编辑器包裹在容器中。 |
initialHeight |
number | string |
0 |
useContainer 为 false 时的编辑器初始高度。 |
initialFocus |
boolean |
false |
初始化后是否请求聚焦。 |
autoCorrect |
boolean |
false |
是否开启自动更正。 |
autoCapitalize |
'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters' |
'off' |
文本自动大写策略。 |
enterKeyHint |
'done' | 'go' | 'next' | 'search' | 'send' |
未声明 | 软键盘回车键类型。 |
pasteAsPlainText |
boolean |
false |
粘贴时是否转为纯文本。 |
defaultParagraphSeparator |
string |
'div' |
回车时插入的 HTML 元素。 |
defaultHttps |
boolean |
true |
无协议的链接是否补全 https://。 |
firstFocusEnd |
boolean |
true |
首次聚焦时光标是否移到文本末尾。 |
contentInset |
{top?: number; bottom?: number; left?: number; right?: number} |
{} |
编辑器内容内边距。 |
style |
StyleProp<ViewStyle> |
{} |
容器或编辑器的样式。 |
editorStyle |
{backgroundColor?: string; color?: string; caretColor?: string; placeholderColor?: string; contentCSSText?: string; initialCSSText?: string; cssText?: string} |
未声明 | 编辑器背景色、文字色、光标色、占位符颜色及内容 CSS。 |
styleWithCSS |
boolean |
未声明 | 使用 style 而非专用标签生成格式化结果。 |
dataDetectorTypes |
DataDetectorTypes | DataDetectorTypes[] |
['none'] |
数据检测类型,透传给底层 WebView。 |
editorInitializedCallback |
() => void |
() => {} |
编辑器初始化完成回调。 |
onChange |
(text: string) => void |
未声明 | 内容变更回调,返回当前 HTML。 |
onPaste |
(data: string) => void |
未声明 | 用户粘贴内容回调。 |
onKeyUp |
({keyCode: number, key: string}) => void |
未声明 | 按键抬起回调。 |
onKeyDown |
({keyCode: number, key: string}) => void |
未声明 | 按键按下回调。 |
onInput |
({data: string, inputType: string}) => void |
未声明 | 输入事件回调。 |
onLink |
(url: string) => void |
未声明 | 链接点击回调。 |
onFocus / onBlur |
() => void |
未声明 | 聚焦、失焦回调。 |
onCursorPosition |
(offsetY: number) => void |
未声明 | 光标位置回调:回传光标所在行的纵坐标(相对 WebView 顶部,见「使用限制」)。 |
onCursorRect |
(rect: {x: number, y: number, width: number, height: number}) => void |
未声明 | 光标矩形回调:回传光标的 x / y / 宽 / 高(页面坐标,见「使用限制」)。 |
onHeightChange |
(height: number) => void |
未声明 | 内容高度变化回调。 |
onMessage |
(message: {type: string; id: string; data?: any}) => void |
未声明 | 编辑器页面自定义消息回调。 |
onMediaLoad |
(event: {type: 'image' | 'video'; url: string}) => void |
未声明 | HarmonyOS 端媒体资源加载成功回调。 |
onMediaError |
(event: {type: 'image' | 'video'; url: string}) => void |
未声明 | HarmonyOS 端媒体资源加载失败回调。 |
onNativeError |
(error: {code: string; message: string; nonce?: number}) => void |
未声明 | HarmonyOS 端原生错误回调。 |
RichToolbar
富文本格式化工具栏组件。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
editor |
React.createRef |
未声明 | RichEditor 实例的 ref。 |
getEditor |
() => RichEditor |
未声明 | 返回 RichEditor 实例的函数,与 editor 二选一。 |
actions |
A[] |
defaultActions |
工具栏允许的操作集合。 |
disabled |
boolean |
false |
是否禁用工具栏。 |
iconTint |
string |
'#71787F' |
未选中图标的颜色。 |
selectedIconTint |
string |
未声明 | 选中图标的颜色。 |
disabledIconTint |
string |
未声明 | 禁用状态图标的颜色。 |
iconSize |
number |
20 |
图标尺寸。 |
iconGap |
number |
16 |
图标间距。 |
iconMap |
Record<string, (icon: IconRecord) => React.Element | ImageSourcePropType> |
未声明 | 自定义图标集合。 |
renderAction |
(action: string, selected: boolean) => React.ReactElement |
未声明 | 自定义操作渲染函数。 |
horizontal |
boolean |
未声明 | 是否横向排列。 |
style |
StyleProp<ViewStyle> |
未声明 | 工具栏样式。 |
flatContainerStyle |
StyleProp<ViewStyle> |
未声明 | 工具栏列表容器样式。 |
itemStyle |
StyleProp<ViewStyle> |
未声明 | 单个操作项样式。 |
unselectedButtonStyle |
StyleProp<ViewStyle> |
未声明 | 未选中按钮样式。 |
selectedButtonStyle |
StyleProp<ViewStyle> |
未声明 | 选中按钮样式。 |
disabledButtonStyle |
StyleProp<ViewStyle> |
未声明 | 禁用按钮样式。 |
onPressAddImage |
() => void |
未声明 | 点击插入图片按钮的回调。 |
onInsertLink |
() => void |
未声明 | 点击插入链接按钮的回调。 |
insertVideo |
() => void |
未声明 | 点击插入视频按钮的回调。 |
children |
React.ReactNode |
未声明 | 工具栏列表之后追加的内容。 |
RichEditor Ref 方法
| 方法 | 说明 |
|---|---|
setContentHTML(html: string) |
设置编辑器 HTML 内容。 |
getContentHtml(): Promise<string> |
读取当前 HTML,已标记为 @deprecated,建议使用 onChange。 |
setPlaceholder(placeholder: string) |
设置占位文本。 |
setContentStyle(styles) |
设置编辑器内容样式。 |
setDisable(disabled: boolean) |
切换编辑器禁用状态。 |
insertText(text: string) |
在光标位置插入文本。 |
insertHTML(html: string) |
在光标位置插入 HTML。 |
insertImage(attributes, style?) |
插入图片。 |
insertVideo(attributes, style?) |
插入视频。 |
insertLink(title: string, url: string) |
插入链接。 |
preCode(type: string) |
插入代码块。 |
setFontSize(size: FONT_SIZE) |
设置选中文本字号,取值为 1–7。 |
setFontName(name: string) |
设置选中文本字体。 |
setForeColor(color: string) |
设置选中文本颜色。 |
setHiliteColor(color: string) |
设置选中文本背景色。 |
focusContentEditor() / blurContentEditor() |
让编辑器获得、失去焦点。 |
dismissKeyboard() |
收起软键盘。 |
command(command: string) |
在编辑器页面中执行脚本,$ 指向 document。 |
commandDOM(command: string) |
在编辑器页面中执行 DOM 操作,$ 指向 document.querySelector。 |
injectJavascript(type: string) |
向编辑器页面注入脚本。 |
registerToolbar(listener: SelectionChangeListener) |
注册选区变化监听。 |
sendAction(type: string, action: string, data?, options?) |
发送自定义操作到编辑器。 |
actions
编辑器操作名称枚举,用于 RichToolbar 的 actions 属性。
| 常量 | 值 | 说明 |
|---|---|---|
actions.setBold |
'bold' |
加粗。 |
actions.setItalic |
'italic' |
斜体。 |
actions.setUnderline |
'underline' |
下划线。 |
actions.setStrikethrough |
'strikeThrough' |
删除线。 |
actions.setSubscript |
'subscript' |
下标。 |
actions.setSuperscript |
'superscript' |
上标。 |
actions.heading1 – actions.heading6 |
'heading1' – 'heading6' |
一到六级标题。 |
actions.setParagraph |
'paragraph' |
正文段落。 |
actions.removeFormat |
'removeFormat' |
清除格式。 |
actions.alignLeft |
'justifyLeft' |
左对齐。 |
actions.alignCenter |
'justifyCenter' |
居中对齐。 |
actions.alignRight |
'justifyRight' |
右对齐。 |
actions.alignFull |
'justifyFull' |
两端对齐。 |
actions.insertBulletsList |
'unorderedList' |
无序列表。 |
actions.insertOrderedList |
'orderedList' |
有序列表。 |
actions.checkboxList |
'checkboxList' |
复选框列表。 |
actions.indent / actions.outdent |
'indent' / 'outdent' |
增加、减少缩进。 |
actions.blockquote |
'quote' |
引用。 |
actions.code |
'code' |
代码块。 |
actions.table |
'table' |
表格。 |
actions.setHR |
'horizontalRule' |
水平分割线的兼容常量:页面侧没有它的实现,工具栏不会内置转发,需要宿主自己接同名回调(onPress/setHR)来插入。 |
actions.insertLine / actions.line |
'line' |
插入水平分割线(<hr>),走编辑器内置派发。 |
actions.insertLink |
'link' |
插入链接。 |
actions.insertImage |
'image' |
插入图片。 |
actions.insertVideo |
'video' |
插入视频。 |
actions.insertText |
'text' |
插入文本。 |
actions.insertHTML |
'html' |
插入 HTML。 |
actions.fontSize |
'fontSize' |
字号。 |
actions.fontName |
'fontName' |
字体。 |
actions.foreColor |
'foreColor' |
文字颜色。 |
actions.hiliteColor |
'hiliteColor' |
文字背景色。 |
actions.undo / actions.redo |
'undo' / 'redo' |
撤销、重做。 |
actions.keyboard |
'keyboard' |
收起键盘。 |
actions.content |
'content' |
编辑器内容区域标识。 |
actions.updateHeight |
'UPDATE_HEIGHT' |
更新编辑器高度。 |
actions.init |
'init' |
编辑器初始化。 |
actions.setEditorHeight |
'SET_EDITOR_HEIGHT' |
设置编辑器高度。 |
actions.setFooterHeight |
'SET_FOOTER_HEIGHT' |
设置底部区域高度。 |
actions.setPlatform |
'SET_PLATFORM' |
设置运行平台。 |
actions.setCustomCSS |
'SET_CUSTOM_CSS' |
设置自定义 CSS。 |
actions.setTextColor |
'SET_TEXT_COLOR' |
设置文本颜色。 |
actions.setBackgroundColor |
'SET_BACKGROUND_COLOR' |
设置背景颜色。 |
actions.setTitlePlaceholder |
'SET_TITLE_PLACEHOLDER' |
设置标题占位文本。 |
actions.setContentPlaceholder |
'SET_CONTENT_PLACEHOLDER' |
设置内容占位文本。 |
actions.setTitleFocusHandler |
'SET_TITLE_FOCUS_HANDLER' |
设置标题聚焦处理。 |
actions.setContentFocusHandler |
'SET_CONTENT_FOCUS_HANDLER' |
设置内容聚焦处理。 |
actions.prepareInsert |
'PREPARE_INSERT' |
插入前准备。 |
actions.restoreSelection |
'RESTORE_SELECTION' |
恢复选区。 |
其他导出项
| 导出项 | 说明 |
|---|---|
defaultActions |
actions 数组,RichToolbar 未指定 actions 时使用的默认操作集合。 |
createHTML(options?) |
生成编辑器页面的 HTML 字符串。 |
getContentCSS() |
返回编辑器页面的默认内容 CSS。 |
快速验证(运行 Example)
前置条件
| 依赖 | 版本要求 |
|---|---|
| Node.js | >=20 |
| React Native for OpenHarmony | 0.72.139 |
| HarmonyOS SDK | API 21+ |
运行步骤
-
获取开发分支源码:
git clone -b react-native-pell-rich-editor_dev https://gitcode.com/hxa-rn/react-native-pell-rich-editor.git -
进入仓库根目录:
cd react-native-pell-rich-editor -
安装仓库根目录依赖,
npm install会同时完成适配包的构建:npm install -
安装tgz:
npm pack -
进入示例工程目录:
cd example -
安装示例工程依赖:
npm install -
生成 React Native JavaScript Bundle:
npm run dev -
使用 DevEco Studio 打开
example/harmony,同步依赖并完成签名配置后,构建运行entry模块。
约束与限制
兼容性
| 依赖 | 要求 |
|---|---|
| React Native for OpenHarmony | >=0.72 |
| HarmonyOS SDK | API 21–24,对应 compatibleSdkVersion 6.0.1(21) 与 targetSdkVersion 6.1.1(24) |
Example 工程 compatibleSdkVersion |
6.0.1(21) |
Example 工程 targetSdkVersion |
6.1.1(24) |
| Node.js | >=18 |
使用限制
command、commandDOM和injectJavascript会执行调用方提供的页面脚本,必须由调用方保证脚本来源可信。onCursorPosition回传的offsetY是光标(选区焦点端)所在行的纵坐标,相对 WebView 顶部;宿主拿到的最终值还会加上 WebView 自身的layout.y。它与onCursorRect由同一次测量产生(规则见下条):折叠光标量「焦点两侧区间」判定所在行,软换行处取下一行行首(与屏幕上光标一致);都量不到时退回该块的元素矩形顶边(此时是块顶而非行),再量不到就不上报,不猜值。onCursorRect回传光标(选区焦点端)的{x, y, width, height},与onCursorPosition由同一次测量产生、并同样加上了 WebView 在 RN 中的偏移(页面坐标)。取值规则:有选区时用引擎给出的选区矩形;折叠光标时不采用引擎的折叠 range 矩形(实测它在软换行处与光标的绘制位置不一致),而是量「焦点两侧区间」——两侧在同一行时x取左侧文字的右边界、y/ 行高取该行;两侧不同行(软换行处)则取下一行行首的x/y/ 行高。量不到位时该回调不上报,不硬凑矩形。- 软换行处(某行行首与上一行行末是同一个字符位置)以光标实际绘制的位置为准:ArkWeb 把该处光标画在下一行行首,本库据此上报该行的
x/y(实测长段落第二行行首为x=10、y=80)。注意引擎自身的折叠 range 矩形在这一点上与绘制位置不一致(它按字符归属报上一行末尾,x=314/y=61),因此本库不采用它,而是量「焦点两侧区间」自行判定。 - 插入代码块(
preCode/actions.code)时,代码块下方会自动补一个空的块级元素(<div><br></div>,标签取决于defaultParagraphSeparator),让宿主和用户都能直接在代码块下方落点编辑;在代码块最后一行空行上回车跳出时,光标同样落进一个块级元素,而不是裸<br>。该空块会出现在getContentHtml与onChange的内容里。 - 输入法行为、光标偏移和部分 HTML 格式化效果可能受 ArkWeb 内核及具体设备差异影响,应在目标设备上验收。
- 远程图片、视频和外部链接依赖网络连通性;编辑器的本地 HTML 编辑不依赖远程网络。
系统权限
本库不依赖额外的 HarmonyOS 系统权限。
开源 License
本项目采用 MIT,与上游项目保持一致。
问题反馈渠道
如在使用过程中遇到问题,请在 GitCode 提交Issue,我们会及时跟进。
- 提交问题时建议附上项目版本、RN 版本、OpenHarmony SDK/API 版本、DevEco Studio 版本、设备信息、复现步骤及相关日志。
- 涉及签名、账号、密钥或用户数据时,请勿在 Issue 中上传敏感信息;可按组织安全流程提交脱敏日志。