深入解析Rich Text编辑器行内样式实现
在前一篇文章中,我们探讨了块级元素的格式化操作,本文将聚焦于行内元素(inline elements)的样式处理。行内样式通常包括加粗、斜体、代码片段或删除线等。在Slate框架中,行内元素被称为"叶子"(leaf),通过renderLeaf属性进行渲染。
构建叶子组件
首先创建专门的叶子渲染组件文件 _leaf.jsx,用于处理不同行内样式:
export const Leaf = ({ attributes, children, leaf }) => {
if (leaf.bold) {
children = <strong>{children}</strong>
}
if (leaf.code) {
children = <code>{children}</code>
}
if (leaf.italic) {
children = <em>{children}</em>
}
if (leaf.underline) {
children = <u>{children}</u>
}
return <span {...attributes}>{children}</span>
}
分离渲染逻辑
为了更好地组织代码,我们将叶子渲染器独立为 _leafRender.jsx:
import React from 'react'
import { Leaf } from './_leaf'
export const renderLeaf = props => {
return <Leaf {...props} />
}
同时整理块级元素渲染器到 _elementRender.jsx:
import React from 'react';
import { CodeElement, DefaultElement } from './_elements';
export const renderElement = props => {
switch (props.element.type) {
case 'code':
return <CodeElement {...props} />
default:
return <DefaultElement {...props} />
}
}
整合编辑器核心
现在更新主组件 SDocer.jsx,引入独立渲染器并添加行内样式快捷键:
import { useState, useCallback } from 'react';
import { createEditor, Editor, Transforms, Element } from 'slate';
import { Slate, withReact, Editable } from 'slate-react';
import { initialValue } from './_configure';
import { renderElement } from './_elementRender';
import { renderLeaf } from './_leafRender';
function SDocer() {
const [editor] = useState(() => withReact(createEditor()));
return (
<Slate editor={editor} initialValue={initialValue}>
<Editable
renderElement={useCallback(renderElement, [])}
renderLeaf={useCallback(renderLeaf, [])}
onKeyDown={event => {
if (!event.ctrlKey) return;
switch (event.key) {
case '`': {
event.preventDefault();
const [match] = Editor.nodes(editor, {
match: n => n.type === 'code',
});
Transforms.setNodes(
editor,
{ type: match ? 'paragraph' : 'code' },
{ match: n => Element.isElement(n) && Editor.isBlock(editor, n) }
);
break;
}
case 'b': {
event.preventDefault();
Editor.addMark(editor, 'bold', true);
break;
}
}
}}
/>
</Slate>
);
}
export default SDocer;
初始化数据配置
更新 _configrue.jsx 以展示混合样式:
export const initialValue = [
{
type: 'paragraph',
children: [{ text: '这是一行段落文字,内容很少,但很重要!!' }],
},
{
type: 'code',
children: [{ text: '这是一代码行段落文字,内容很少,但很重要!!' }],
},
{
type: 'paragraph',
children: [
{ text: 'This is editable ' },
{ text: 'rich', bold: true },
{ text: ' text, ' },
{ text: 'much', italic: true },
{ text: ' better than a ' },
{ text: '<textarea>', code: true, underline: true },
{ text: '<textarea>', underline: true },
{ text: '!' },
],
},
];
通过上述实现,编辑器已经能够响应 Ctrl+B 快捷键进行加粗操作,同时保留了块级元素的格式切换功能。随着功能扩展,编辑器的能力也逐步增强。