Custom Block Components
自定义块级组件
Draft is designed to solve problems for straightforward rich text interfaces like comments and chat messages, but it also powers richer editor experiences like Facebook Notes.
Draft 旨在解决简单的富文本接口的问题,像是评论和聊天信息,但它也赋予了更丰富的编辑器体验,像是 Facebook 笔记。
Users can embed images within their Notes, either loading from their existing Facebook photos or by uploading new images from the desktop. To that end, the Draft framework supports custom rendering at the block level, to render content like rich media in place of plain text.
用户可以在他们的笔记中嵌入图片,无论是从他们已经存在的 Facebook 照片中读取还是从桌面上传新图片。为此,Draft 框架支持 block 级别的自定义渲染,来渲染富媒体内容,替代了纯文本。
The TeX editor in the Draft repository provides a live example of custom block rendering, with TeX syntax translated on the fly into editable embedded formula rendering via the KaTeX library.
在 Draft 仓库里的 TeX 编辑器 提供了一个自定义块级渲染的在线示例。通过 KaTeX library ,TeX 语法被动态的编译成渲染的可编辑的嵌入公式。
A media example is also available, which showcases custom block rendering of audio, image, and video.
也提供了一个 多媒体示例 ,它展示了音频,图片和视频的自定义块级渲染。
By using a custom block renderer, it is possible to introduce complex rich interactions within the frame of your editor.
通过使用一个自定义的block渲染器,在你的编辑器里引入复杂的富文本接口成为可能。
Custom Block Components
自定义块级组件
Within the
Editor
component, one may specify theblockRendererFn
prop. This prop function allows a higher-level component to define custom React rendering forContentBlock
objects, based on block type, text, or other criteria.
在 Editor
组件中,可以指定 blockRendererFn
属性。这个属性方法允许一个更高级别的组件指定自定义的,以 block 类型,文字或其他标准为基础的,对 ContentBlock
对象的 React 渲染。
For instance, we may wish to render
ContentBlock
objects of type'atomic'
using a customMediaComponent
.
比如,我们也许希望以 “atomic”
类型,使用自定义的 MediaComponent
渲染 ContentBlock
对象。
function myBlockRenderer(contentBlock) {
const type = contentBlock.getType();
if (type === 'atomic') {
return {
component: MediaComponent,
editable: false,
props: {
foo: 'bar',
},
};
}
}
// Then...
import {Editor} from 'draft-js';
class EditorWithMedia extends React.Component {
...
render() {
return <Editor ... blockRendererFn={myBlockRenderer} />;
}
}
If no custom renderer object is returned by the
blockRendererFn
function,Editor
will render the defaultDraftEditorBlock
text block component.
如果没有自定义的渲染器对象被 blockRendererFn
方法返回,Editor
会渲染默认的 DraftEditorBlock
文本块级组件。
The
component
property defines the component to be used, while the optionalprops
object includes props that will be passed through to the rendered custom component via theprops.blockProps
sub property object. In addition, the optionaleditable
property determines whether the custom component iscontentEditable
.
这个 component
的属性决定了组件何时被使用,同时这个可选的 props
对象包含了,通过 props.blockProps
子属性对象进入被渲染的自定义组件的属性。此外,这个可选的 editable
属性决定了自定义组件是否是 contentEditable
。
It is strongly recommended that you use
editable: false
if your custom component will not contain text.
如果你的自定义组件不包含文本,强烈建议您使用 editable:false
。
If your component contains text as provided by your
ContentState
, your custom component should compose aDraftEditorBlock
component. This will allow the Draft framework to properly maintain cursor behavior within your contents.
如果你的组件包含被你的 ContentState
提供的文本,你的自定义组件应该构成一个 DraftEditorBlock
组件。这会要求 Draft 框架在你的内容里适当的调整光标行为。
By defining this function within the context of a higher-level component, the props for this custom component may be bound to that component, allowing instance methods for custom component props.
通过在一个高级组件的上下文中定义方法,这个自定义组件的属性可以被绑定到其他组件,允许它使用自定义组件属性的实例方法。
Defining custom block components
定义自定义块级组件
Within
MediaComponent
, the most likely use case is that you will want to retrieve entity metadata to render your custom block. You may apply an entity key to the text within a'atomic'
block duringEditorState
management, then retrieve the metadata for that key in your custom componentrender()
code.
在 MediaComponent
中,最常用的例子是你想要检索检索实体元数据以渲染你的自定义 block 。在 EditorState
的管理中,你也许会应用一个实体 key 到一个 'atomic'
的 block 的文本上,然后在你的自定义组件的 render()
代码中检索那个 key 的元数据。
class MediaComponent extends React.Component {
render() {
const {block, contentState} = this.props;
const {foo} = this.props.blockProps;
const data = contentState.getEntity(block.getEntityAt(0)).getData();
// Return a <figure> or some other content using this data.
// 返回一个 <figure> 或其他使用这个数据的内容
}
}
The
ContentBlock
object and theContentState
record are made available within the custom component, along with the props defined at the top level. By extracting entity information from theContentBlock
and theEntity
map, you can obtain the metadata required to render your custom component.
这个 ContentBlock
对象和 ContentState
记录可以在自定义组件中获取,通过定义好的顶级属性。通过从 ContentBlock
和 Entity
的遍历提取实体信息,你可以获取所需的元数据,从而渲染到你的自定义组件上。
Retrieving the entity from the block is admittedly a bit of an awkward API, and is worth revisiting.
从 block 上检索实体的 API 不可否认的有点笨拙,但这是值得的。
Recommendations and other notes
建议和其他注意点
If your custom block renderer requires mouse interaction, it is often wise to temporarily set your
Editor
toreadOnly={true}
during this interaction. In this way, the user does not trigger any selection changes within the editor while interacting with the custom block. This should not be a problem with respect to editor behavior, since interacting with your custom block component is most likely mutually exclusive from text changes within the editor.
如果你的自定义 block 渲染器需要鼠标交互,在交互中临时设置你的 Editor
为 readOnly = { true }
是明智的。这样,用户不会在编辑器中触发自定义 block 的交互。这不应该是编辑行为方面的问题,因为你的自定义 block 组件的交互和编辑器中文字的变化很可能是互斥的。
The recommendation above is especially important for custom block renderers that involve text input, like the TeX editor example.
上述的建议对于包含文字输入的自定义 block 渲染特别重要,例如 TeX 编辑器示例。
It is also worth noting that within the Facebook Notes editor, we have not tried to perform any special SelectionState rendering or management on embedded media, such as rendering a highlight on an embedded photo when selecting it. This is in part because of the rich interaction provided on the media itself, with resize handles and other controls exposed to mouse behavior.
值得一提的是,在 Facebook 的笔记编辑器中,我们没有尝试执行任何特殊的 SelectionState 渲染或管理到嵌入的多媒体中,比如渲染一个高亮到选择的嵌入照片上。这在一定程度上是因为多媒体本身提供的富文本交互,比如缩放的处理和其他暴露到鼠标行为上的控制。
Since an engineer using Draft has full awareness of the selection state of the editor and full control over native Selection APIs, it would be possible to build selection behavior on static embedded media if desired. So far, though, we have not tried to solve this at Facebook, so we have not packaged solutions for this use case into the Draft project at this time.
因为一个使用 Draft 的工程师有着对于编辑器的选择状态的完整认识,以及对于原生 Selection APIs 的完整控制,所以如果需要,在内嵌多媒体上构建静态的选择行为是可能的。到目前为止,在 Facebook ,我们还没有尝试解决这一点,所以在 Draft 项目中,我们还没有这个示例的完整的解决方案。