react-page 编辑器核心组件 `<Editor />` 完全指南:props 详解、只读/编辑双模式与 JSON 数据格式
前端UI组件【免费下载链接】react-pageNext-gen, highly customizable content editor for the browser - based on React and written in TypeScript. WYSIWYG on steroids.项目地址https://gitcode.com/gh_mirrors/rea/react-page点击查看免费下载Editor /是 react-page基于 React 与 TypeScript 打造的下一代浏览器内容编辑器中第一个需要实例化的组件同时承担内容编辑与内容展示两种职责。本文将以 docs/editor.md 为主线结合 Editor.tsx 源码与 示例应用完整讲解该组件的全部 props、只读与编辑模式切换机制、多语言方案以及底层 JSON 内容格式帮助你直接上手构建自己的可嵌入内容编辑器。组件定位一个组件两种形态react-page 采用单元cell作为内容组织的基本单位而Editor /是所有单元、插件与 UI 控件的容器。官方文档明确指出它既可以用于编辑内容也可以通过设置readOnly为true用于展示内容。最简单的用法是传入一个富文本编辑器插件——react-page 预置了基于 Slate 的slate插件作为cellPlugin同时可选image插件用于上传图片或通过 URL 加载图片。下面的代码取自 simple.tsx演示了最小可运行形态import Editor, { Value } from react-page/editor; import react-page/editor/lib/index.css; // 富文本插件Slate import slate from react-page/plugins-slate; import react-page/plugins-slate/lib/index.css; // 图片展示插件 import image from react-page/plugins-image; import react-page/plugins-image/lib/index.css; // 定义本编辑器可用的插件集合 const cellPlugins [slate(), image]; export default function SimpleExample() { const [value, setValue] useStateValue(null); // 编辑模式 Editor cellPlugins{cellPlugins} value{value} onChange{setValue} /; // 展示模式只读 Editor cellPlugins{cellPlugins} value{value} readOnly /; }从 Editor.tsx 源码可以看到组件默认值定义为readOnly false、value null、onChange null这意味着编辑模式是默认形态。注意这里的slate()需要以函数调用的方式执行Slate 插件工厂会返回一个插件实例而image直接传入即可。编辑与查看的参考示例官方文档为两种形态分别提供了可直接运行的示例页面编辑示例simple.tsx演示valueonChange受控编辑只读示例readonly.tsx演示readOnly展示模式在 readonly.tsx 中内容来自预置的demoSimpleReadOnly样例见 demoSimpleReadOnly.tsx其注释明确提示你通常应该从某个 api / 端点 / 数据库加载这个内容——即只读模式下value往往来自服务端持久化数据。Props 详解value: Value编辑器要展示的内容。该数据可以来自任何来源例如文件、数据库或 API。它是对整页内容的 JSON 表示详见下文 Internal JSON details。官方文档强调这份数据是不透明的opaque在正常情况下不应直接手工修改也不要依赖其内部结构。值得补充的是editor 包入口 还导出了若干与value相关的实用工具便于在受控场景下安全操作内容createValue创建新的内容值migrateValue将旧版本内容迁移到最新 schema配合Migration使用deepEquals深度比较两个内容值objIsNode判断对象是否为合法节点结构。onChange: (newValue: Value) void每当编辑器产生新数据时触发的回调用于把最新内容保存下来。当readOnly为true时该 prop 不是必需的。对应源码位于 callbacks.ts其中还定义了第二个可选回调onChangeLang: (l: string) void在用户切换当前语言时触发可用于同步外部状态。readOnly: boolean设置为true时内容不可编辑适合用于展示场景。官方文档特别强调了它的性能价值只读模式下编辑相关代码根本不会被加载因此在使用 webpack 等打包器时会带来体积缩减。若在运行时把readOnly置回false编辑 UI 会即时加载并显示从而可以在展示与编辑两种模式间无缝切换。这一机制的实现细节非常值得关注。Editor.tsx 通过lazyLoad动态导入EditableEditor而EditableEditor被替换为轻量的HTMLRenderer组件总是以只读方式首次挂载useState(true)useEffect同步官方注释说明这是为了避免 SSR服务端渲染问题——服务端渲染时不会加载任何编辑逻辑当readOnly变化时再决定渲染HTMLRenderer还是EditableEditor即便切换到编辑模式HTMLRenderer仍作为fallback传入保证编辑代码动态加载期间的流畅过渡。官方文档还给出了一个典型实战场景直接在公开页面上提供编辑能力。做法是判断当前用户是否为发布者若是则显示一个按钮点击后把readOnly置为false并提供onChange保存内容——这样展示与编辑共用同一套组件与同一份value。cellPlugins: CellPlugin[]当前编辑器可用的CellPlugin数组。react-page 自带一些内置插件并提供了极强的扩展系统用于创建展示任意内容的自定义插件。通常内置的 slate 插件 非常适合富文本编辑但也可以替换为其他编辑器插件。更多可能性参见内置 Cell 插件自定义 Cell 插件从源码看cellPlugins同时被用于只读渲染与编辑渲染两条路径在 Editor.tsx 中它被放入renderOptions传给HTMLRenderer与EditableEditor两侧。插件数组的顺序会影响工具栏中的展示顺序开发者可以通过CellPlugin的id、title、Renderer、controls如 conditionalForm.tsx 中演示的 autoform 条件表单等字段控制行为。lang当内容需要多语言时传入一个语言 id例如en。需要与languages配合使用。值得注意的是源码中的默认逻辑Editor.tsx 中lang的取值优先级是langprop languages[0].langdefault。也就是说即便不传任何语言配置内容也会被归入default语言键下参见demoSimpleReadOnly中dataI18n.undefined的写法实际为 legacy 的default键。languages一个{lang: string, label: string}数组列出编辑器支持的所有语言const LANGUAGES [ { lang: en, label: English, }, { lang: de, label: Deutsch, }, ];这样编辑用户可以随时选择语言。官方文档强调了这种逐 cell 多语言设计的核心优势任何 cell 默认显示默认语言内容除非为该语言创建了另一个版本。也就是说多语言是按 cell 粒度而非整页粒度进行的用户只需要翻译真正需要翻译的段落避免了传统 CMS把整页复制到另一种语言的痛点。此外单元格还可以按语言隐藏cells can be hidden per language。完整用法可参考 i18n.tsx 示例其中lang取LANGUAGES[0].lang即en并配合languages一起传给Editor /。cellSpacing接受一个数字或{x: number, y: number}对象控制单元格之间的间距cellSpacing { x: 15, // 水平方向单元格间距 y: 20, // 垂直方向单元格间距 };在 Editor.tsx 中cellSpacing的默认值为null即无额外间距并同时参与只读与编辑两条渲染路径的renderOptions。参考实现位于 cellSpacing.tsx该示例通过 AutoForm 动态调节cellSpacingX/cellSpacingY配合 CSS 轮廓.react-page-cell-inner { outline: 1px solid red }可以直观看到间距对网格布局的影响。仓库中customLayoutPluginWithCellSpacing插件则展示了自定义布局插件如何与间距配合。uiTranslator接受(label: string) string类型的函数为编辑器开启 i18n 支持——所有界面标签都会经过该函数包装。对应源码类型定义位于 options.ts注释说明key参数当前是英文翻译文本。官方文档给出的翻译实现来自 i18n 示例如下const TRANSLATIONS: { [key: string]: string } { Edit blocks: 编辑, Add blocks: 添加, Move blocks: 移动, Resize blocks: 调整大小, Preview blocks: 预览模式, }; const uiTranslator useCallback((label?: string) { if (TRANSLATIONS[label] ! undefined) { return TRANSLATIONS[label]; } return ${label}(to translate); }, []);这个实现展示了一个实用技巧未覆盖的标签会回退为${label}(to translate)形式方便在开发期发现缺失的翻译条目。uiTranslator的默认值为null见 defaultOptions.ts即默认不进行翻译。childConstraints实验性接受对象childConstraints: { maxChildren: number, }当编辑器中已有行数少于maxChildren时才显示用于新增 cell 的 () 按钮。官方明确标注其当前限制它目前只控制按钮的显示与否通过拖拽仍然可以添加新 cell后续会被重新设计因此视为实验特性。源码定义见 constraints.ts注释同样标注 EXPERIMENTAL实验性默认值在 defaultOptions.ts 中为{}。更多可选 props源码补充在 options.ts 中还可以看到文档之外、但日常使用频率很高的配置项均可在Editor /上直接传入配置项默认值作用allowResizeInEditMode/allowMoveInEditModetrue/true编辑模式下是否允许调整尺寸 / 拖拽移动单元格zoomEnabled、zoomFactorstrue、[1, 0.75, 0.5, 0.25]是否启用缩放功能及其倍率undoRedoEnabledtrue是否启用撤销 / 重做editEnabled/insertEnabled/layoutEnabled/resizeEnabled/previewEnabled均true侧边栏各功能开关sidebarPositionrightAbsolute侧边栏位置rightAbsolute/rightRelative/leftAbsolute/leftRelativehideEditorSidebarfalse是否隐藏编辑器侧边栏shouldShowErrorInCellsfalse单元格渲染出错时是否在页面显示错误否则仅 console 输出dndBackendHTML5Backend覆盖 react-dnd 的拖拽后端uiThemedefaultTheme自定义 MUI 主题store/middlewarenull/[]传入自定义 Redux store / 中间件未来可能废弃以上默认值均可在 defaultOptions.ts 中逐一核对。内部 JSON 格式详解Internal JSON details整页内容以易于解析的 JSON 形式存储由两部分组成data数据观众实际看到的内容metadata元数据渲染数据所需的辅助信息例如 id、版本、插件信息等。这份 JSON 同样被官方视为不透明结构不应在正常情况下手工编辑。它有以下几个重要特性不包含任何表现层信息——即不存储 CSS可移植JSON 数据可以复制到新文档中从而为版本化或模板化创建当前文档的克隆。优势对比传统富文本编辑器产出的是内容数据与外观样式捆绑在一起的原始 HTML 标记而 JSON 表示更干净、体积小得多且不带观点unopiniated——同一份 JSON 可以用不同的渲染组件以不同的方式呈现。这正是 react-page 能够把编辑与展示分离、并支持自定义渲染器的根基。下面两份 JSON 是官方文档给出的完整示例。示例 1简单文本内容下面这张图展示了该 JSON 渲染出的实际效果一个标题 一段正文{ id: obknih, version: 1, rows: [ { id: b27eia, cells: [ { id: e9htzt, size: 12, plugin: { id: ory/editor/core/content/slate, version: 1 }, dataI18n: { default: { slate: [ { type: HEADINGS/HEADING-TWO, children: [ { text: This is a heading } ] }, { type: PARAGRAPH/PARAGRAPH, children: [ { text: This is some paragraph text } ] } ] } }, rows: [], inline: null } ] } ] }关键结构解读顶层id是内容文档 idversion是内容 schema 版本配合migrateValue做迁移判断rows数组包含一行行内cells数组包含一个占满 12 栅格的 cellsize: 12plugin.id标识该 cell 使用的插件这里是 Slate 富文本plugin.version是插件版本dataI18n是按语言组织的数据——default键下存放默认语言数据若存在其他语言版本会出现对应的语言键如en、dedataI18n.default.slate内部正是 Slate 的节点树HEADINGS/HEADING-TWO、PARAGRAPH/PARAGRAPH等类型节点rows与inline用于嵌套布局如列内再套行、行内元素。对照 demoSimpleReadOnly.tsx 可以看到真实样例数据的结构与上述完全一致只是dataI18n使用 legacy 的undefined键、并在data中携带了对齐信息align: center。示例 2包含图片的内容下图展示了文本行 图片行组合的渲染效果{ id: obknih, version: 1, rows: [ { id: b27eia, cells: [ { id: e9htzt, size: 12, plugin: { id: ory/editor/core/content/slate, version: 1 }, dataI18n: { default: { slate: [ { type: HEADINGS/HEADING-TWO, children: [ { text: This is a heading } ] }, { type: PARAGRAPH/PARAGRAPH, children: [ { text: This is some paragraph text } ] } ] } }, rows: [], inline: null } ] }, { id: 5j8lyl, cells: [ { id: k0t2gk, size: 12, plugin: { id: ory/editor/core/content/image, version: 1 }, dataI18n: { default: { src: https://www.nasa.gov/sites/default/files/styles/full_width/public/thumbnails/image/mars2020-sample-tubes.jpg?itokSiZDKmmG } }, rows: [], inline: null } ] } ] }对比示例 1 可以看出图片 cell 的plugin.id变为ory/editor/core/content/image而dataI18n.default中存放的是图片地址字段src。不同插件在dataI18n中存放的数据形状由插件自身定义——这正是JSON 不带观点、由渲染组件决定呈现方式的体现。图片插件源码位于 image 插件目录其createPlugin.tsx定义了src等字段的 schema 与 Renderer。自定义编辑器 UIcomponents实验性如果需要对编辑器 UI 做更精细的控制可以覆盖部分内部组件。官方文档给出三条重要提醒始终作为最后手段使用Use this always as a last resort因为覆盖后可能无法获得 react-page 的全部功能动手前先提交 Issue说明你究竟想定制或修改什么——很可能存在更简单的解决方案甚至能为 react-page 带来一个新特性从而共享创新目前可替换的组件只有一个BottomToolbar渲染底部工具栏的组件负责展示插件控件和一些单元格操作。如果希望替换更多组件官方欢迎提交 Issue 或 Pull Request 来扩展该列表。对应类型定义位于 components.ts默认值为{}见 defaultOptions.ts。小结与建议的下一步Editor /是整个 react-page 的入口组件一个组件同时覆盖编辑与展示readOnly切换驱动了编辑代码的按需加载cellPlugins决定内容能力边界lang/languages/dataI18n构成逐 cell 粒度的多语言体系cellSpacing控制网格节奏底层 JSON 则保证了内容的可移植性与渲染无关性。上手时建议按以下路径实践从 simple.tsx 开始跑通编辑 →onChange拿到 JSON → 存入数据库的最小闭环用 readonly.tsx 验证只读展示与按需加载结合 i18n.tsx 与 cellSpacing.tsx 熟悉多语言与布局间距深入阅读 内置插件文档 与 自定义 Cell 插件文档按需扩展内容类型若要做服务端渲染或内容迁移参考 server-side-rendering.md 以及 index.tsx 中导出的createValue、migrateValue、deepEquals等工具。赞分享前端UI组件【免费下载链接】react-pageNext-gen, highly customizable content editor for the browser - based on React and written in TypeScript. WYSIWYG on steroids.项目地址https://gitcode.com/gh_mirrors/rea/react-page点击查看免费下载相关推荐JSON Editor数组编辑器完全指南表格、选择器、复选框等多种模式JSON Editor数组编辑器完全指南表格、选择器、复选框等多种模式 JSON Editor是一个强大的基于JSON Schema的编辑器它提供了丰富的数前端UI组件React-Page 编辑器组件深度解析React Page 编辑器组件深度解析 前言 React Page 是一个功能强大的 React 页面构建器它提供了直观的拖放界面来创建和编辑网页内容。本文前端UI组件推荐React Email Editor —— 拖放式邮件编辑器组件推荐React Email Editor —— 拖放式邮件编辑器组件 如果你正在寻找一个强大且开发者友好的视觉邮件构建工具来集成到你的React应用中那么R前端UI组件上一篇SpacetimeDB × Godot 完整教程从零构建可承载数百名玩家的 Blackholio 多人在线游戏下一篇Vant 4 Divider 分割线组件完全指南从基础用法到主题定制创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →