┌──────────────────────────────────────────────────────────┐ │ 📄 shadcn/directory/udecode/plate/(guides)/static.cn │ └──────────────────────────────────────────────────────────┘
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
<PlateStatic> 是一个快速、只读的 React 组件,用于渲染 Plate 内容,针对服务器端或 React Server Component (RSC) 环境进行了优化。它避免了客户端编辑逻辑,并对节点渲染进行记忆化,相比在只读模式下使用 <Plate>,具有更好的性能。
它是 serializeHtml 用于 HTML 导出的核心部分,非常适合任何需要非交互式、展示性 Plate 内容视图的服务器或 RSC 环境。
_memo 和结构检查,仅重新渲染已更改的节点。<PlateStatic>启用静态渲染的最快方法是使用 BaseEditorKit,它包含了预配置的基础插件,可以与服务器端渲染无缝配合。
import { createSlateEditor, PlateStatic } from 'platejs';
import { BaseEditorKit } from '@/components/editor/editor-base-kit';
const editor = createSlateEditor({
plugins: BaseEditorKit,
value: [
{ type: 'h1', children: [{ text: '服务器渲染的标题' }] },
{ type: 'p', children: [{ text: '此内容是静态渲染的。' }] },
],
});
// 静态渲染
export default function MyStaticPage() {
return <PlateStatic editor={editor} />;
}
查看完整的服务器端静态渲染示例:
<ComponentSource name="slate-to-html" /> </Steps>使用 createSlateEditor 初始化一个 Slate 编辑器实例,包含所需的插件和组件。这类似于为交互式 <Plate> 组件使用 usePlateEditor。
import { createSlateEditor } from 'platejs';
// 导入所需的基础插件(例如 BaseHeadingPlugin、MarkdownPlugin)
// 确保在服务器环境中不要从 /react 子路径导入。
const editor = createSlateEditor({
plugins: [
// 在此添加您的基础插件列表
// 示例:BaseHeadingPlugin, MarkdownPlugin.configure({...})
],
value: [ // 示例初始值
{
type: 'p',
children: [{ text: '来自静态 Plate 编辑器的问候!' }],
},
],
});
如果您的交互式编辑器使用客户端组件(例如带有 use client 或事件处理程序),您必须创建静态的、服务器安全的等效组件。这些组件应该渲染纯 HTML,不包含浏览器特定的逻辑。
import React from 'react';
import type { SlateElementProps } from 'platejs';
export function ParagraphElementStatic(props: SlateElementProps) {
return (
<SlateElement {...props}>
{props.children}
</SlateElement>
);
}
为标题、图片、链接等创建类似的静态组件。
创建一个对象,将插件键或节点类型映射到相应的静态 React 组件,然后将其传递给编辑器。
import { ParagraphElementStatic } from './ui/paragraph-node-static';
import { HeadingElementStatic } from './ui/heading-node-static';
// ... 导入其他静态组件
export const staticComponents = {
p: ParagraphElementStatic,
h1: HeadingElementStatic,
// ... 为所有元素和叶子类型添加映射
};
<PlateStatic>使用 <PlateStatic> 组件,提供配置了组件的 editor 实例。
import { PlateStatic } from 'platejs';
import { createSlateEditor } from 'platejs';
// import { BaseHeadingPlugin, ... } from '@platejs/basic-nodes'; // 等等
import { staticComponents } from '@/components/static-components';
export default async function MyStaticPage() {
// 示例:获取或定义编辑器值
const initialValue = [
{ type: 'h1', children: [{ text: '服务器渲染的标题' }] },
{ type: 'p', children: [{ text: '静态渲染的内容。' }] },
];
const editor = createSlateEditor({
plugins: [/* 您的基础插件 */],
components: staticComponents,
value: initialValue,
});
return (
<PlateStatic
editor={editor}
style={{ padding: 16 }}
className="my-plate-static-content"
/>
);
}
<Callout type="note" title="值覆盖">
如果您直接向 `<PlateStatic>` 传递 `value` 属性,它将覆盖 `editor.children`。
```tsx
<PlateStatic
editor={editor}
value={[
{ type: 'p', children: [{ text: '覆盖的内容。' }] }
]}
/>
```
</Callout>
<PlateStatic> 通过记忆化提升性能:
<ElementStatic> 和 <LeafStatic> 都被 React.memo 包装。_memo 字段: 在元素或叶子上设置 node._memo = true(或任何稳定值)可以强制 Plate 跳过重新渲染该特定节点,即使其内容发生变化。这对于更新的细粒度控制很有用。PlateView对于需要与静态内容进行最小交互的情况,请使用 <PlateView>。该组件包装了 <PlateStatic> 并添加了客户端事件处理程序来处理用户交互,同时保持静态渲染的性能优势。
import { createStaticEditor } from 'platejs';
import { PlateStatic } from 'platejs';
import { BaseEditorKit } from '@/components/editor/editor-base-kit';
import { InteractiveViewer } from './interactive-viewer';
export default async function DocumentPage() {
const content = await fetchDocument(); // 您的文档数据
// 服务器端静态编辑器
const editor = createStaticEditor({
plugins: BaseEditorKit,
value: content,
});
return (
<div className="grid grid-cols-2 gap-4">
{/* 纯静态渲染 - 无交互性 */}
<div>
<h2>静态视图(服务器渲染)</h2>
<PlateStatic editor={editor} />
</div>
{/* 交互式视图 - 在客户端渲染 */}
<div>
<h2>交互式视图</h2>
<InteractiveViewer value={content} />
</div>
</div>
);
}
'use client';
import { usePlateViewEditor } from 'platejs/react';
import { PlateView } from 'platejs/react';
import { BaseEditorKit } from '@/components/editor/editor-base-kit';
export function InteractiveViewer({ value }) {
const editor = usePlateViewEditor({
plugins: BaseEditorKit,
value,
});
return <PlateView editor={editor} />;
}
PlateView 的主要功能'use client' 指令PlateStatic 进行渲染usePlateViewEditor 配合使用: 创建一个为仅查看 React 组件优化的静态编辑器ViewPlugin,提供事件处理功能PlateStatic vs. PlateView vs. Plate + readOnly| 方面 | <PlateStatic> | <PlateView> | <Plate> + readOnly |
| --------------------- | ----------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------ |
| 环境 | 服务器/客户端(SSR/RSC 安全) | 仅客户端 | 仅客户端 |
| 交互性 | 无 | 最小(选择、复制、工具栏等) | 完整的交互功能(仅浏览器) |
| 浏览器 API | 不使用 | 最小(事件处理程序) | 完全使用 |
| 性能 | 最佳 - 仅静态 HTML | 良好 - 静态渲染 + 事件委托 | 较重 - 完整的编辑器内部结构 |
| 打包体积 | 最小 | 小 | 最大 |
| 使用场景 | 服务器渲染、HTML 导出 | 需要基本交互的客户端内容 | 需要所有功能的完整只读编辑器 |
| 推荐 | 无任何交互的 SSR/RSC | 需要轻量级交互的客户端内容 | 具有复杂交互需求的客户端 |
在 Next.js App Router(或类似的 RSC 环境)中,<PlateStatic> 可以直接在服务器组件中使用:
import { PlateStatic } from 'platejs';
import { createSlateEditor } from 'platejs';
// 示例基础插件(确保非 /react 导入)
// import { BaseHeadingPlugin } from '@platejs/basic-nodes';
import { staticComponents } from '@/components/static-components'; // 您的静态组件映射
export default async function Page() {
// 在服务器端获取或定义内容
const serverContent = [
{ type: 'h1', children: [{ text: '在服务器上渲染! 🎉' }] },
{ type: 'p', children: [{ text: '此内容是静态的且在服务器端渲染。' }] },
];
const editor = createSlateEditor({
// plugins: [BaseHeadingPlugin, /* ...其他基础插件 */],
plugins: [], // 添加您的基础插件
components: staticComponents,
value: serverContent,
});
return (
<PlateStatic
editor={editor}
className="my-static-preview-container"
/>
);
}
这会在服务器上将内容渲染为 HTML,而无需为 PlateStatic 本身提供客户端 JavaScript 包。
serializeHtml 配合使用要生成完整的 HTML 字符串(例如用于电子邮件、PDF 或外部系统),请使用 serializeHtml。它在内部使用 <PlateStatic>。
import { createSlateEditor, serializeHtml } from 'platejs';
import { staticComponents } from '@/components/static-components';
// import { BaseHeadingPlugin, ... } from '@platejs/basic-nodes';
async function getDocumentAsHtml(value: any[]) {
const editor = createSlateEditor({
plugins: [/* ...您的基础插件... */],
components: staticComponents,
value,
});
const html = await serializeHtml(editor, {
// editorComponent: PlateStatic, // 可选:默认为 PlateStatic
props: { className: 'prose max-w-none' }, // 示例:向根 div 传递属性
});
return html;
}
// 使用示例:
// const mySlateValue = [ { type: 'h1', children: [{ text: '我的文档' }] } ];
// getDocumentAsHtml(mySlateValue).then(console.log);
有关更多详细信息,请参阅 HTML 序列化指南。
<PlateStatic> 属性import type React from 'react';
import type { Descendant } from 'slate';
import type { PlateEditor } from 'platejs/core'; // 根据您的设置调整导入
interface PlateStaticProps extends React.HTMLAttributes<HTMLDivElement> {
/**
* Plate 编辑器实例,通过 `createSlateEditor` 创建。
* 必须包含与要渲染的内容相关的插件和组件。
*/
editor: PlateEditor;
/**
* 可选的 Plate `Value`(`Descendant` 节点数组)。
* 如果提供,将用于渲染而不是 `editor.children`。
*/
value?: Descendant[];
/** 根 `div` 元素的内联 CSS 样式。 */
style?: React.CSSProperties;
// 其他 HTMLDivElement 属性如 `className`、`id` 等也受支持。
}
editor:使用 createSlateEditor 创建的 PlateEditor 实例,包括组件配置。value:可选。如果提供,此 Descendant 节点数组将被渲染,覆盖当前在 editor.children 中的内容。║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
╚══════════════════════════════════════════════════════════════════════════════════════════════╝