Slate Editor
默认的 Payload 编辑器目前基于 Lexical。本文档 是关于我们旧的基于 Slate 的编辑器。你可以继续使用它,因为它仍然受支持,或者你可以 查看可选的迁移指南从 Slate 迁移到 Lexical(推荐)。
要使用 Slate 编辑器,首先需要安装它:
npm install --save @payloadcms/richtext-slate
安装完成后,你可以将其传递给你的顶层 Payload 配置:
import { buildConfig } from 'payload'
import { slateEditor } from '@payloadcms/richtext-slate'
export default buildConfig({
collections: [
// 你的 collections 配置
],
// 将 Slate 编辑器传递给根配置
editor: slateEditor({}),
})
以下是如何逐个字段安装 Slate 编辑器并自定义其选项的示例:
import type { CollectionConfig } from 'payload'
import { slateEditor } from '@payloadcms/richtext-slate'
export const Pages: CollectionConfig = {
slug: 'pages',
fields: [
{
name: 'content',
type: 'richText',
// 在此处传递 Slate 编辑器并进行相应配置
editor: slateEditor({
admin: {
elements: [
// 在此处自定义 Slate 编辑器中允许的元素
],
leaves: [
// 在此处自定义 Slate 编辑器中允许的叶子节点
],
},
}),
},
],
}
管理选项
elements
elements
属性用于指定在管理面板中应为字段提供哪些内置或自定义的 SlateJS 元素。
Payload 中默认可用的 elements
包括:
h1
h2
h3
h4
h5
h6
blockquote
link
ol
ul
textAlign
indent
relationship
upload
textAlign
leaves
leaves
属性用于指定在 Admin Panel 中启用的内置或自定义 SlateJS leaves。
Payload 中默认可用的 leaves
包括:
bold
(加粗)code
(代码)italic
(斜体)strikethrough
(删除线)underline
(下划线)
link.fields
该属性允许将字段作为富文本编辑器中链接的额外字段保存。当设置此属性时,这些字段会显示在一个模态框中,可以通过点击链接元素上的"编辑"按钮打开。
link.fields
可以是一个字段数组(在这种情况下,所有定义的字段将被追加到默认字段下方),也可以是一个函数,该函数接受默认字段作为唯一参数,并返回定义要使用的全部字段的数组(从而提供覆盖默认字段的机制)。
带有自定义字段的 RichText 链接
upload.collections[collection-name].fields
该属性允许将字段作为富文本编辑器中上传字段的元数据保存。当设置此属性时,这些字段会显示在一个模态框中,可以通过点击上传元素上的"编辑"按钮打开。
使用上传元素的 RichText 字段
显示配置字段的 RichText 上传元素模态框
关系元素
内置的 relationship
元素是一种强大的方式,可以直接在你的富文本编辑器中引用其他文档。
上传元素
与 relationship
元素类似,upload
元素是一种用户友好的方式来引用支持上传的集合,其 UI 专门为媒体/基于图片的上传设计。
提示:
默认情况下,集合会自动允许在富文本关系型和上传元素中被选择。如果你想禁止某个集合在富文本字段中被引用,可以将集合的管理选项 enableRichTextLink 和 enableRichTextRelationship 设置为 false。
关系型和上传元素会动态填充到你的富文本字段内容中。在 REST 和 Local API 中,任何存在的 RichText relationship
或 upload
元素都会遵循你传递的 depth
选项,并相应地被填充。在 GraphQL 中,每个 richText
字段都接受一个 depth
参数供你使用。
文本对齐元素
文本对齐默认不包含在内,可以通过将 textAlign
添加到元素列表中来为富文本编辑器添加该功能。TextAlign 会修改现有元素,在生成的 JSON 中包含一个新的 textAlign
字段。该字段可以与其他元素和叶子节点结合使用,将内容定位到左侧、居中或右侧。
指定允许的元素和叶子节点
要指定该字段允许使用的默认元素或叶子节点,可以定义包含你希望启用的每个元素或叶子节点名称的字符串数组。要指定自定义元素或叶子节点,可以传递一个包含所有相应属性的对象,如下所述。查看示例了解所有这些如何工作。
构建自定义元素和叶子节点
你可以设计和构建自己的 Slate 元素和叶子节点,通过自定义功能来扩展编辑器。为此,首先请阅读 SlateJS 文档 并查看 Slate 示例,全面熟悉 SlateJS 编辑器。
一旦你掌握了相关的基本概念,就可以将自定义的元素和叶子节点传递给你的字段管理配置。
自定义元素和叶子节点都通过以下配置定义:
Property | Description |
---|---|
name * | 作为该元素默认 type 使用的名称。 |
Button * | 在富文本工具栏中渲染的 React 组件。 |
plugins | 提供给富文本编辑器的插件数组。 |
type | 覆盖 name 默认类型的自定义类型 |
自定义 Element
还需要设置 Element
属性为一个 React 组件,该组件将在富文本编辑器内部作为 Element
渲染。
自定义 Leaf
对象遵循类似的模式,但需要你定义 Leaf
属性而非 Element
。
指定自定义 Type
允许你通过向 JSON 对象添加额外字段来扩展自定义元素。
示例
collections/ExampleCollection.ts
import type { CollectionConfig } from 'payload'
import { slateEditor } from '@payloadcms/richtext-slate'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
fields: [
{
name: 'content', // 必填
type: 'richText', // 必填
defaultValue: [
{
children: [{ text: '这是该字段的默认内容' }],
},
],
required: true,
editor: slateEditor({
admin: {
elements: [
'h2',
'h3',
'h4',
'link',
'blockquote',
{
name: 'cta',
Button: CustomCallToActionButton,
Element: CustomCallToActionElement,
plugins: [
// 该元素所需的任何插件放在这里
],
},
],
leaves: [
'bold',
'italic',
{
name: 'highlight',
Button: CustomHighlightButton,
Leaf: CustomHighlightLeaf,
plugins: [
// 该叶子节点所需的任何插件放在这里
],
},
],
link: {
// 向 Link 元素注入自定义字段
fields: [
{
name: 'rel',
label: 'Rel 属性',
type: 'select',
hasMany: true,
options: ['noopener', 'noreferrer', 'nofollow'],
},
],
},
upload: {
collections: {
media: {
fields: [
// 你想在 `media` 集合的上传元素上保存的任何字段
],
},
},
},
},
}),
},
],
}
生成 HTML
由于 Rich Text 字段以 JSON 格式保存内容,你需要自行将其渲染为 HTML。以下是一个将 Rich Text 内容生成 JSX/HTML 的示例:
import React, { Fragment } from "react";
import escapeHTML from "escape-html";
import { Text } from "slate";
const serialize = (children) =>
children.map((node, i) => {
if (Text.isText(node)) {
let text = (
<span dangerouslySetInnerHTML={{ __html: escapeHTML(node.text) }} />
);
if (node.bold) {
text = <strong key={i}>{text}</strong>;
}
if (node.code) {
text = <code key={i}>{text}</code>;
}
if (node.italic) {
text = <em key={i}>{text}</em>;
}
// 在这里处理其他叶子节点类型...
return <Fragment key={i}>{text}</Fragment>;
}
if (!node) {
return null;
}
switch (node.type) {
case "h1":
return <h1 key={i}>{serialize(node.children)}</h1>;
// 在这里遍历所有标题...
case "h6":
return <h6 key={i}>{serialize(node.children)}</h6>;
case "blockquote":
return <blockquote key={i}>{serialize(node.children)}</blockquote>;
case "ul":
return <ul key={i}>{serialize(node.children)}</ul>;
case "ol":
return <ol key={i}>{serialize(node.children)}</ol>;
case "li":
return <li key={i}>{serialize(node.children)}</li>;
case "link":
return (
<a href={escapeHTML(node.url)} key={i}>
{serialize(node.children)}
</a>
);
default:
return <p key={i}>{serialize(node.children)}</p>;
}
});
注意:
上述示例展示的是如何渲染为 JSX,虽然对于纯 HTML 模式也类似。 只需移除 JSX 并返回 HTML 字符串即可!
内置 SlateJS 插件
Payload 提供了一些内置的 SlateJS 插件,可以通过扩展这些插件来更轻松地开发你自己的元素(elements)和叶子节点(leaves)。
shouldBreakOutOnEnter
Payload 内置的所有标题元素都允许通过"硬回车"来"跳出"当前激活的元素。例如,当你在 h1
元素中按下 enter
键时,将会"跳出" h1
元素,然后你可以继续以默认的段落元素进行输入。
如果你想在自己的自定义元素中使用这个功能,可以通过向你的 element
添加自定义插件来实现,如下面的"大号正文"元素示例:
customLargeBodyElement.js
:
import Button from './Button'
import Element from './Element'
import withLargeBody from './plugin'
export default {
name: 'large-body',
Button,
Element,
plugins: [
(incomingEditor) => {
const editor = incomingEditor
const { shouldBreakOutOnEnter } = editor
editor.shouldBreakOutOnEnter = (element) =>
element.type === 'large-body' ? true : shouldBreakOutOnEnter(element)
return editor
},
],
}
在上面的代码中,我们创建了一个名为 large-body
的自定义 SlateJS 元素。这个元素可能会在你的应用前端渲染稍大一些的正文内容。我们为它传递了名称、按钮和元素——此外,我们还传递了一个包含单个 SlateJS 插件的 plugins
数组。
该插件本身扩展了 Payload 内置的 shouldBreakOutOnEnter
Slate 函数,将自己的元素名称添加到按下 enter
键时应该"跳出"的元素列表中。
TypeScript
如果你正在构建自己的自定义富文本元素或叶子节点,可能会用到以下类型:
import type {
RichTextCustomElement,
RichTextCustomLeaf,
} from '@payloadcms/richtext-slate'