作为一名新时代农民工,几乎每个人都有自己的博客站点,而博客最重要的功能就是文档编辑,实现文档编辑无外乎Markdown
、富文本编辑器
两种模式。其中富文本编辑器使用起来比较简单,不需要额外了解各种语法,对非技术人员来说容易上手,本文就着重介绍一下富文本编辑器框架————Slate,它不仅可以帮助我们自定义实现富文本效果,而且还能实现类似于Markdown一样的语法输入。
说起Slate,可能很多人不了解,但是说起前端富文本插件库
wangEditor
以及飞书文档
,大家就不陌生了,这两款产品底层技术采用的就是Slate。
安装
Slate 本身是支持各种框架的,但是官方提供了React版本的库实现,我们就以React版本示例:
1npm install slate slate-react
初始化编辑器
初始化编辑节点,并赋予编辑器默认内容。
注意默认内容的数据结构需要符合Slate的格式,其基本元素类型类似于HTML,包括块节点(Blocks)、行内节点(inlines)。可以通过
type
字段区分不同的元素,后续我们的自定义节点就可以通过该字段区分。
1// index.js
2import { useState } from "react";
3import { createEditor } from "slate";
4import { Slate, Editable, withReact } from "slate-react";
5import './index.css'
6const SlateBox = ( ) => {
7 const [editor] = useState(() => withReact(createEditor()))
8 const [editorText, setEditorText] = useState([
9 {
10 type: 'paragraph',
11 children: [{
12 text: '这是一个slate内容的结构示例,每一段都是通过文本节点或者自定义节点的数组组成,文本节点必须包含text属性。' }]
13 }
14 ])
15 return (
16 <Slate editor={editor} initialValue={editorText}>
17 <Editable className="editor-container" />
18 </Slate>
19)
20}
21export default SlateBox;
优化编辑器样式:
1/* index.css */
2*{
3 box-sizing: border-box;
4}
5.editor-container{
6 width: 100vw;
7 height: 100vh;
8 padding: 8px;
9 background: #000;
10 color: #fff;
11}
目前的效果图:

添加工具栏
富文本编辑器就是通过各种快捷按钮实现文本的不同效果,因此我们在编辑器顶部添加一个工具栏,展示一个高亮块按钮。
1js
2
3复制代码
4
5`// index.js import { useState } from "react"; import { createEditor } from "slate"; import { Slate, Editable, withReact } from "slate-react"; import { Button } from 'antd' import { BulbOutlined } from '@ant-design/icons' import './index.css' const SlateBox = ( ) => { const [editor] = useState(() => withReact(createEditor())) const [editorText, setEditorText] = useState([ { type: 'paragraph', children: [{ text: '这是一个slate内容的结构示例,每一段都是通过文本节点或者自定义节点的数组组成,文本节点必须包含text属性。' }] } ]) const addHighBlock = ( ) => { console.log('添加高亮块') } return ( <Slate editor={editor} initialValue={editorText}> <div className="editor-toolbar"> <Button icon={<BulbOutlined />} className="menu-btn" type="text" onClick={addHighBlock}></Button> </div> <Editable className="editor-container" /> </Slate> ) } export default SlateBox;`
实现工具栏样式:
1css
2
3复制代码
4
5`/* index.css */ *{ box-sizing: border-box; } .editor-toolbar{ background: #242426; height: 40px; display: flex; align-items: center; padding: 0 8px; } .menu-btn{ color: #fff !important; } .menu-btn:hover{ background: #000 !important; } .editor-container{ width: 100vw; height: calc(100vh - 40px); padding: 8px; background: #000; color: #fff; border: 1px solid transparent; } .editor-container:focus-visible{ outline: none; border-color: #fff; }`
如约而至的效果图:

重点来了,自定义我们的高亮节点
Slate提供了一个reanderElement
方法,通过修改节点数据结构的type
类型或者添加属性,就可以让我们轻松实现一个自定义节点。
1js
2
3复制代码
4
5`// index.js import { useCallback, useState } from "react"; import { createEditor, Transforms } from "slate"; import { Slate, Editable, withReact, DefaultElement } from "slate-react"; import { Button } from 'antd' import { BulbOutlined } from '@ant-design/icons' import './index.css' // 自定义高亮节点 const HighBlock = (props) => { return ( // 添加slate相关属性 <div className="high-block" {...props.attributes}> <BulbOutlined /> {/* 展示高亮节点下的内容 */} {props.children} </div> ) } const SlateBox = ( ) => { const [editor] = useState(() => withReact(createEditor())) const [editorText, setEditorText] = useState([ { type: 'paragraph', children: [{ text: '这是一个slate内容的结构示例,每一段都是通过文本节点或者自定义节点的数组组成,文本节点必须包含text属性。' }] } ]) const renderElement = useCallback(props => { switch (props.element.type) { case 'highBlock': return <HighBlock {...props} /> default: return <DefaultElement {...props} /> } }, []) const addHighBlock = ( ) => { Transforms.insertNodes(editor, { type: 'highBlock', children: [{ text: '高亮节点默认值' }] }) } return ( <Slate editor={editor} initialValue={editorText}> <div className="editor-toolbar"> <Button icon={<BulbOutlined />} className="menu-btn" type="text" onClick={addHighBlock}></Button> </div> <Editable className="editor-container" renderElement={renderElement} /> </Slate> ) } export default SlateBox;`
添加我们自定义节点的样式:
1css
2
3复制代码
4
5`/* index.css */ *{ box-sizing: border-box; } .editor-toolbar{ background: #242426; height: 40px; display: flex; align-items: center; padding: 0 8px; } .menu-btn{ color: #fff !important; } .menu-btn:hover{ background: #000 !important; } .editor-container{ width: 100vw; height: calc(100vh - 40px); padding: 8px; background: #000; color: #fff; border: 1px solid transparent; } .editor-container:focus-visible{ outline: none; border-color: #fff; } .high-block{ display: flex; padding: 16px; border-radius: 8px; background: rgba(242, 150, 44, .17); border: 1px solid #845117; margin: 16px 0; line-height: 24px; } .high-block .anticon-bulb{ color: #eb8f26; line-height: 28px; margin-right: 4px; }`
最后的实现效果图

以上只是一个Slate的简单入门示例,它还提供了许多诸如对选区、路径等操作方法,轻松实现滑动选择文字出现文字多音字提示等功能,大家可以去探索一下。
个人笔记记录 2021 ~ 2025