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