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

news2024/9/25 17:18:33

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

这时候当我们键入任何内容后在 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 (
    <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 等等,一切皆有可能。

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

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

相关文章

用Java语言创建的Spring Boot项目中,如何传递数组呢??

问题&#xff1a; 用Java语言创建的Spring Boot项目中&#xff0c;如何传递数组呢&#xff1f;&#xff1f; 在这个思路中&#xff0c;其实&#xff0c;Java作为一个后端开发的语言&#xff0c;没必要着重于如何传入&#xff0c;我们主要做的便是对传入的数组数据进行处理即可…

力扣hot6---双指针

题目&#xff1a; TLE做法&#xff08;哈希两重for循环&#xff09; 标签虽然说是用双指针&#xff0c;但是第一个想法真就不是双指针呀。。。就感觉这道题很像&#xff1a; 力扣hot1--哈希-CSDN博客 于是就用了类似的想法&#xff1a; 首先要排个序&#xff0c;至于为什么要…

MySQL 如何从 Binlog 找出变更记录并回滚

文章目录 前言1. 案例模拟1.1 确认信息1.2 下载 Binlog1.3 准备环境1.4 注册 Binlog1.5 准备结构信息1.6 Python 订阅1.7 输出结果展示 2. 原理解析2.1 程序设计2.2 模块版本 总结 前言 最近有研发同学问我&#xff1a;有一个问题&#xff0c;想查一个 ID 为 xxxx 的 sku 什么…

Linux(CentOS为例)环境下 Git提交代码加速,使用FastGithub,运行报错解决

当你的在服务器上使用Git进行推送时&#xff0c;时常会出现超时错误。这里使用FastGithub 首先下载FastGithub 这个软件作者不是为什么删除了GithUb的仓库&#xff0c;这个链接还有。下载Linux版本的 FastGithub Linux&#xff0c;Windows版本 下载完毕后解压 ./fastgithu…

Linux课程四课---Linux开发环境的使用(gcc/g++编译器的相关)

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

[VSCode插件] 轻量级静态博客 - MDBlog

MDBlog VSCode插件&#xff0c;基于Markdown的轻量级静态博客系统&#xff0c;同时支持导出为可以部署的静态博客。 仓库 MDBlog 1. Features 博客基础功能&#xff1a;分类管理、文章管理、自动生成索引快捷指令&#xff1a;快捷输入表格、mermaid、wavedrom、代码块发布&a…

Photoshop 2023:重塑创意,引领数字艺术新纪元

在数字艺术的浩瀚星空中&#xff0c;Adobe Photoshop 2023&#xff08;简称PS 2023&#xff09;如同一颗璀璨的新星&#xff0c;为Mac和Windows用户带来了前所未有的创意体验。这款强大的图像处理软件不仅继承了前作的精髓&#xff0c;更在细节上进行了诸多创新&#xff0c;让每…

前端el-date-picker传递的日期格式不是自己想要的格式

解决方法&#xff1a; 添加format和value-format属性进行解决。 format“YYYY-MM-DD” value-format“YYYY-MM-DD” 注意&#xff1a;日期格式要用大写&#xff01;&#xff01;&#xff01;&#xff01;用小写会出现错误&#xff0c;不能回填选择的日期&#xff0c;会直接传入…

【 buuctf-swp】

wget 是什么东西呢&#xff1f; 那就直接过滤 http 流&#xff0c;并全部导出&#xff0c;点击 save all在导出来的一大堆里发现个 zip&#xff0c;需要输入密码&#xff0c;macOS 一大特点就是&#xff0c;如果是伪加密&#xff0c;随便输入一个密码就可以解压缩&#xff0c;…

Redis7 实现持久化的三种方式

1、概述 1.1、Redis持久化的重要性 数据恢复&#xff1a;Redis是一个内存数据库&#xff0c;如果系统或服务宕机&#xff0c;内存中的数据将会丢失。Redis的持久化机制可以把数据保存到磁盘上&#xff0c;以便在系统重启后恢复数据。这是Redis持久化最基本也是最重要的功能。…

基于阿里云OSS上传图片实战案例

一、案例描述 基于Springboot框架实现一个上传图片到阿里云服务端保存的小案例。 二、准备工作 基于Springboot免费搭载轻量级阿里云OSS数据存储库&#xff08;将本地文本、照片、视频、音频等上传云服务保存&#xff09;-CSDN博客 三、代码 新建这两个类&#xff1a;一个…

MySQL:开始深入其数据(四)select子查询

select眼熟吧?(都三节了) 又开始学习了 在 MySQL 中&#xff0c;子查询&#xff08;subquery&#xff09;是指在一个查询内嵌套另一个完整的 SELECT 语句。子查询可以嵌套在 SELECT、INSERT、UPDATE、DELETE 语句中&#xff0c;用于从内部查询结果中获取数据&#xff0c;进而完…

新加坡大带宽服务器概览

随着全球互联网的迅猛发展&#xff0c;服务器作为支撑网络应用的重要基础设施&#xff0c;扮演着越来越重要的角色。新加坡&#xff0c;作为亚洲四小龙之一&#xff0c;其服务器市场也备受关注。特别是新加坡的大带宽服务器&#xff0c;更是受到了众多企业和个人的青睐。那么&a…

LeetCode -- 79.单词搜索

1. 问题描述 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水…

SNAP:如何批量预处理Sentinel2 L2A数据集并输出为TIFF文件?

我的需求 我目前就是希望下载哨兵2号数据&#xff0c;然后在SNAP中进行批量提取真彩色波段并输出为TIFF文件。 数据集下载说明 目前哨兵网站似乎进行了一大波更新&#xff0c;连网站都换了&#xff0c;网址如下&#xff1a; https://dataspace.copernicus.eu/ 打开后界面如…

Linux课程四课---Linux开发环境的使用(自动化构建工具-make/Makefile的相关)

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

C++进阶(三) 二叉搜索树

一、二叉搜索树 1.1 二叉搜索树概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节…

【论文】A Survey of Monte Carlo Tree Search Methods阅读笔记

本文主要是将有关蒙特卡洛树搜索的文献&#xff08;2011年之前&#xff09;进行归纳&#xff0c;概述了核心算法的推导&#xff0c;给出了已经提出的许多变化和改进的一些结构&#xff0c;并总结了MCTS方法已经应用于的博弈和其他领域的结果。 蒙特卡洛树搜索是一种通过在决策…

Java 石头剪刀布小游戏

一、任务 编写一个剪刀石头布游戏的程序。程序启动后会随机生成1~3的随机数&#xff0c;分别代表剪刀、石头和布&#xff0c;玩家通过键盘输入剪刀、石头和布与电脑进行5轮的游戏&#xff0c;赢的次数多的一方为赢家。若五局皆为平局&#xff0c;则最终结果判为平局。 二、实…

深入理解与应用工厂方法模式

文章目录 一、模式概述**二、适用场景****三、模式原理与实现****四、采用工厂方法模式的原因****五、优缺点分析****六、与抽象工厂模式的比较**总结 一、模式概述 ​ 工厂方法模式是一种经典的设计模式&#xff0c;它遵循面向对象的设计原则&#xff0c;特别是“开闭原则”&…