React富文本编辑器开发(六)

现在,相关的基础知识我们应该有个大概的了解了,但离我们真正的开发出一个实用型的组件还有一段距离,不过不用担心,我们离目标已经越来越近。
以现在我们所了解的内容而言,或许你发现了一个问题,就是我们的编辑器的内容如何保存的问题,数据的保存是最重要的一个环节,无法保存的数据意义不大。我们以本地数据持久化为例来说明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 (<Slateeditor={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)}}}><EditablerenderElement={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;

这时候当我们键入任何内容后在 localStoragecontent 中的内容都能看到变化。如下所示:

在这里插入图片描述

虽然现在我们的内容能够实时的保存,但是页面一刷新还是还原了,这是显而易见的,因为我们并没有在组件初始化时从我们的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 (<Slateeditor={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)}}}><EditablerenderElement={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 (<Slateeditor={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))}}}><EditablerenderElement={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 等等,一切皆有可能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/717545.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CentOS配网报错:network is unreachable

常用命令&#xff1a; 打开&#xff1a; cd /etc/sysconfig/network-scripts/ 修改&#xff1a; vim ifcfg-ens33 打开修改&#xff1a; vim /etc/sysconfig/network-scripts/ifcfg-ens33 保存&#xff1a; 方法1&#xff1a;ESCZZ&#xff08;Z要大写&#xff09; 方…

Linux:地址空间的转换以及线程的理解和使用

文章目录 线程的理解地址空间的转换问题总结 线程的优点线程的缺点线程的健壮性问题 本篇主要进行对于进程和线程的理解&#xff0c;以及对于线程的一部分使用方法和使用的原理 线程的理解 首先回顾前面一篇的内容中&#xff0c;对于进程的基本认识&#xff1a; 什么是线程&…

【LeetCode:2368. 受限条件下可到达节点的数目 + BFS】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

SpringBoot-yaml语法

1.概念 在Springboot的项目中&#xff0c;配置文件有以下几种格式&#xff1a; Application.propertiesApplication.yamlApplication.yml 其中官方推荐我们使用yaml的格式(因为能表示的数据类型很多样) 2.基本语法 # yaml形式的配置文件# 普通的key-value&#xff08;分号之后…

用numpy搭建自己的神经网络

搭建之前的基础与思考 构建模型的基本思想&#xff1a; 构建深度学习的过程&#xff1a;产生idea&#xff0c;将idea转化成code&#xff0c;最后进行experiment&#xff0c;之后根据结果修改idea&#xff0c;继续idea–>code–>experiment的循环&#xff0c;直到最终训练…

matplotlib条形图

matplotlib条形图 假设你获取到了2017年内地电影票房前20的电影(列表a)和电影票房数据(列表b), 那么如何更加直观的展示该数据? from matplotlib import pyplot as plta ["Wolf Warrior 2", "Fast and Furious 8", "Kung Fu Yoga", "Jo…

线性表——单链表的增删查改

本节复习链表的增删查改 首先&#xff0c; 链表不是连续的&#xff0c; 而是通过指针联系起来的。 如图&#xff1a; 这四个节点不是连续的内存空间&#xff0c; 但是彼此之间使用了一个指针来连接。 这就是链表。 现在我们来实现链表的增删查改。 目录 单链表的全部接口…

位运算---求n的二进制表示中第k位是1还是0 (lowbit)

操作&#xff1a; 先把第k位移到最后一位&#xff08;右边第一位&#xff09; 看个位是1还是0 lowbit(x)&#xff1a;返回x的最右边的1。 原理&#xff1a; 其中 &#xff0c;意思是 是 的补码。 就可以求出最右边的一位1。 应用&#xff1a; 当中 的个数。 int re…

AI-数学-高中-33概率-事件的关系与运算

原作者视频&#xff1a;【概率】【一数辞典】2事件的关系与运算_哔哩哔哩_bilibili 事件&#xff1a; 和/并事件&#xff1b;积/交事件&#xff1b;互诉事件&#xff1b;对立(补集)事件&#xff1b;

【详识JAVA语言】面向对象程序三大特性之二:继承

继承 为什么需要继承 Java中使用类对现实世界中实体来进行描述&#xff0c;类经过实例化之后的产物对象&#xff0c;则可以用来表示现实中的实体&#xff0c;但是 现实世界错综复杂&#xff0c;事物之间可能会存在一些关联&#xff0c;那在设计程序是就需要考虑。 比如&…

04.其他方案

其他方案 1.事务状态表调⽤⽅重试接收⽅幂等 介绍 调⽤⽅维护⼀张事务状态表&#xff08;或者说事务⽇志、⽇志流⽔&#xff09;&#xff0c;在每次调⽤之前&#xff0c;落盘⼀条事务流⽔&#xff0c;⽣成⼀个全局的事务ID 事务开始之前的状态是Begin&#xff0c;全部结束之…

码垛工作站:食品生产企业的转型助推器

在当今高度自动化的工业生产中&#xff0c;码垛工作站的应用正逐渐成为一种趋势。某食品生产企业在面临市场竞争加剧、人工成本上升等多重压力下&#xff0c;决定引入码垛工作站&#xff0c;以期实现生产流程的升级与变革。 一、码垛工作站引入背景 该企业主要从事休闲食品的…

【贪心算法】Leetcode 455.分发饼干 376. 摆动序列 53. 最大子数组和

【贪心算法】Leetcode 455 分发饼干 376. 摆动序列【规律很多】53. 最大子数组和 455 分发饼干局部最优推全局最优&#xff1a;尽量用大饼干去满足大胃口的小朋友 376. 摆动序列【规律很多】思想&#xff1a;注意考虑一个坡度留首尾两个点、平坡、首尾 53. 最大子数组和【好思想…

15.网络游戏逆向分析与漏洞攻防-网络通信数据包分析工具-发送通信数据包至分析工具

上一个内容&#xff1a;14.数据包分析工具界面与通信设计 码云地址&#xff08;master 分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/titan 码云版本号&#xff1a;2d6491e3c51a1a7ab4da0ee6dc4cf566a80fd6e1 代码下载地址&#xff0c;在 titan 目录下&…

模版进阶C++

非类型模版 之前我们写的模版都是在不知道模版&#xff08;类&#xff09;中有的变量的类型是什么的时候&#xff0c;我们先用模版参数定义&#xff0c;当类实例化的时候在传参确认 非类型模版&#xff1a;模版参数定义的时候也可以定义整型类型&#xff08;c20之后才支持其…

奇点云:SAFe框架下,我们对平台软件工程生产线做了4项改造

导读&#xff1a; 客户规模扩大&#xff0c;如何保证大数据软件产品和服务质量始终如一&#xff1f;几乎所有成长中的软件厂商&#xff0c;尤其是需要通过私有化部署交付的厂商&#xff0c;都会面临这个问题。正如《人月神话》中多次表明的&#xff0c;单纯地增加人手、扩大团队…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的植物病害检测系统(Python+PySide6界面+训练代码)

摘要&#xff1a;开发高效的植物病害检测系统对于提升农业生产效率和作物健康管理意义重大。本篇博客详细阐述了如何运用深度学习技术构建一个植物病害检测系统&#xff0c;并提供了完整的实现代码。该系统基于先进的YOLOv8算法&#xff0c;对YOLOv7、YOLOv6、YOLOv5进行了性能…

考研数学——高数:微分方程

一、一阶线性微分方程 两种形式&#xff1a; 非齐次&#xff1a; 齐次&#xff1a; 推导过程 推导公式的过程一般由特殊到一般&#xff1a;所以先求解齐次方程的解 &#xff08;然后对等式两边同时积分&#xff09; 再来求非齐次方程的解&#xff0c;由…

03-grafana的下拉列表选项制作-grafana的变量

一、准备环境 为了实现下拉列表筛选的样例&#xff0c;我们监控两个linux节点&#xff1b; 目前&#xff0c;我们已经有了一个节点了&#xff0c;再添加一个&#xff1b; 二、grafana的仪表盘变量 如果想给仪表盘自定义下拉列表&#xff0c;那么&#xff0c;需要设置变量&#…

线上问题——2021-12-27 父子线程共用线程池导致死锁故障

一、事故现象 从早上6点开始edu-wings-admin的timer-task和mq就开始报警任务堆积&#xff0c;且数量持续上升&#xff0c;到6点50左右mq也开始告警&#xff0c;8点左右发现问题&#xff0c;开始排查&#xff0c;直到11点才找到问题&#xff0c;任务开始正常消费。 二、事故影响…