赞
踩
现在,相关的基础知识我们应该有个大概的了解了,但离我们真正的开发出一个实用型的组件还有一段距离,不过不用担心,我们离目标已经越来越近。
以现在我们所了解的内容而言,或许你发现了一个问题,就是我们的编辑器的内容如何保存的问题,数据的保存是最重要的一个环节,无法保存的数据意义不大。我们以本地数据持久化为例来说明Slate中的这一相关功能。
到目前为止,我们的编辑一但在页面刷新的情况下就会还原到初始状态,即使我们做了诸多的内容编辑也会付诸东流。我们以本地存储为例,为<Slate/>
组件添加onChange
事件,如下所示:
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'; import { Helper } from './_helper'; function SDocer() { const [editor] = useState(() => withReact(createEditor())); return ( <Slate editor={editor} initialValue={initialValue} onChange={value => { const isAstChange = editor.operations.some( op => 'set_selection' !== op.type ) if (isAstChange) { const content = JSON.stringify(value) localStorage.setItem('content', content) } }} > <Editable renderElement={useCallback(renderElement, [])} renderLeaf={useCallback(renderLeaf, [])} onKeyDown={event => { if (!event.ctrlKey) return; switch (event.key) { case '`': { event.preventDefault() Helper.toggleCodeBlock(editor); break } case 'b': { Helper.toggleBoldMark(editor); break } } }} /> </Slate> ) } export default SDocer;
这时候当我们键入任何内容后在 localStorage
中 content
中的内容都能看到变化。如下所示:
虽然现在我们的内容能够实时的保存,但是页面一刷新还是还原了,这是显而易见的,因为我们并没有在组件初始化时从我们的LocalStore中读取数据,所以就只显示初始变量中的内容。我们调入localStorage中的内容就行了:
const initDatas = () => JSON.parse(localStorage.getItem('content')) || initialValue;
并把这个内容用useMemo
无依赖的静态化,如下所示:
import { useState, useCallback, useMemo } 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'; import { Helper } from './_helper'; const initDatas = () => JSON.parse(localStorage.getItem('content')) || initialValue; function SDocer() { const [editor] = useState(() => withReact(createEditor())); return ( <Slate editor={editor} initialValue={useMemo(initDatas, [])} onChange={value => { const isAstChange = editor.operations.some( op => 'set_selection' !== op.type ) if (isAstChange) { const content = JSON.stringify(value) localStorage.setItem('content', content) } }} > <Editable renderElement={useCallback(renderElement, [])} renderLeaf={useCallback(renderLeaf, [])} onKeyDown={event => { if (!event.ctrlKey) return; switch (event.key) { case '`': { event.preventDefault() Helper.toggleCodeBlock(editor); break } case 'b': { Helper.toggleBoldMark(editor); break } } }} /> </Slate> ) } export default SDocer;
这个时候当你编辑后再刷新页面,内容就不在发生变化了。这样的json数据很适用,利于网络传输。但有时你可能特立独行,就是要走不一样的道路,也是可以的,我们可以自定义序列化 serialize
和 反序列化 deserialize
,比如我想保存一个纯文格式,或许就要这样做了:
新建一个工具文件 _untils.jsx
import { Node } from 'slate' export const serialize = value => { return ( value .map(n => Node.string(n)) .join('\n') ) } export const deserialize = string => { const content = string || '' return content.split('\n').map(line => { return { children: [{ text: line }], } }) }
上面的工具很简单,就是把所有的节点纯文本化。以换行符分割。把上面的工具应用于Slate
,如下所示:
import { useState, useCallback, useMemo } 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'; import { Helper } from './_helper'; import { serialize, deserialize } from './_untils'; // const initDatas = () => JSON.parse(localStorage.getItem('content')) || initialValue; const initDatas = () => deserialize(localStorage.getItem('content')) || ""; function SDocer() { const [editor] = useState(() => withReact(createEditor())); return ( <Slate editor={editor} initialValue={useMemo(initDatas, [])} onChange={value => { const isAstChange = editor.operations.some( op => 'set_selection' !== op.type ) if (isAstChange) { // const content = JSON.stringify(value) localStorage.setItem('content', serialize(content)) } }} > <Editable renderElement={useCallback(renderElement, [])} renderLeaf={useCallback(renderLeaf, [])} onKeyDown={event => { if (!event.ctrlKey) return; switch (event.key) { case '`': { event.preventDefault() Helper.toggleCodeBlock(editor); break } case 'b': { Helper.toggleBoldMark(editor); break } } }} /> </Slate> ) } export default SDocer;
结果符合预期。相似的做法,我也可以将内容序列化HTML、Markdown 等等,一切皆有可能。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。