这篇文章讨论怎么定制 Draft 的 block 渲染。Block 渲染用于定义支持的 block 类型和它们的渲染器,以及将解析之后的的内容转换为已知的 Draft block 类型。
当解析内容或者使用 convertFromHTML
时,Draft 会将标签和 Draft block 进行匹配,将解析后的内容转化为已知的 block 渲染类型。
默认的 block 渲染表
HTML 标签 | Draft block 类型 |
---|---|
<h1/> |
header-one |
<h2/> |
header-two |
<h3/> |
header-three |
<h4/> |
header-four |
<h5/> |
header-five |
<h6/> |
header-six |
<blockquote/> |
blockquote |
<pre/> |
code-block |
<figure/> |
atomic |
<li/> |
unordered-list-item,ordered-list-item** |
<div/> |
unstyled* |
- Block 类型建立在父级元素
* - 任何不在上边列表的block类型都会被当做
unstyled
配置 block 渲染列表
Draft 默认的 block 渲染可以通过给 Editor
组件传入类型为 Immutable Map 的 blockRender
prop 来重写。
例如改写默认的 block 渲染。
// The example below deliberately only allows
// 'heading-two' as the only valid block type and
// updates the unstyled element to also become a h2.
const blockRenderMap = Immutable.Map({
'header-two': {
element: 'h2'
},
'unstyled': {
element: 'h2'
}
});
class RichEditor extends React.Component {
render() {
return (
<Editor
...
blockRenderMap={blockRenderMap}
/>
);
}
}
除了重写 block 类型,我们还能够添加自定义的 block 类型。通过 DefaultDraftBlockRenderMap 来新建一个blockRenderMap。
扩展默认的 block render map。
const blockRenderMap = Immutable.Map({
'section': {
element: 'section'
}
});
// Include 'paragraph' as a valid block and updated the unstyled element but
// keep support for other draft default block types
const extendedBlockRenderMap = Draft.DefaultDraftBlockRenderMap.merge(blockRenderMap);
class RichEditor extends React.Component {
render() {
return (
<Editor
...
blockRenderMap={extendedBlockRenderMap}
/>
);
}
}
当 Draft 解析一个已经被解析的 html,它将 html 元素转化为 Draft block 类型。如果你想让其它的标签也能转化为指定的 block 类型,你可以在 block config 中添加 aliasedElements
。
unstyled block 类型别名的使用:
'unstyled': {
element: 'div',
aliasedElements: ['p'],
}
自定义 block wrappers
默认的情况下,html 标签被用来包裹 block 类型。通过 blockRenderMap,React 组件也能够用来包裹EditorBlock。
在解析或者使用 convertFromHTML
时 html 会被扫描,来匹配特定的标签。一个 wrapper 会用来承载特定的block 类型。例如:
Draft 使用 <ol/>
或者 <ul/>
来包裹 <li/>
。 wrapper 也可以在其它类型的 block上使用。
在自定义 block 类型上使用 React 组件作为 wrapper 的例子:
class MyCustomBlock extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className='MyCustomBlock'>
{/* here, this.props.children contains a <section> container, as that was the matching element */}
{this.props.children}
</div>
);
}
}
const blockRenderMap = Immutable.Map({
'MyCustomBlock': {
// element is used during paste or html conversion to auto match your component;
// it is also retained as part of this.props.children and not stripped out
element: 'section',
wrapper: <MyCustomBlock />,
}
});
// keep support for other draft default block types and add our myCustomBlock type
const extendedBlockRenderMap = Draft.DefaultDraftBlockRenderMap.merge(blockRenderMap);
class RichEditor extends React.Component {
...
render() {
return (
<Editor
...
blockRenderMap={extendedBlockRenderMap}
/>
);
}
}