react使用react-quill富文本编辑器自定义上传图片,添加handlers后编辑器不显示问题

本文主要是介绍react使用react-quill富文本编辑器自定义上传图片,添加handlers后编辑器不显示问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Quill介绍

Quill 是一款 API 驱动、功能强大的现代富文本编辑器。它具有易于拓展、各平台表现一致性等优点。Quill 官方 1.0 版本于 2016 年 9 月发布,目前在 Github 上有41.8k Star。

官网地址:Quill - Your powerful rich text editor

github仓库地址:GitHub - slab/quill: Quill is a modern WYSIWYG editor built for compatibility and extensibility 

api文档地址:API - Quill Rich Text Editor

基本概念

Module配置

Quill 是以可拓展性和定制化为理念进行设计的。它尽可能简洁地实现了的编辑器的核心功能,并暴露接口供开发者进行定制化开发。这些核心功能就是通过 Module 来组织管理的。主要的 Module 有这些:

  1. Toolbar,它的主要功能是让用户方便快捷地对文本进行格式化。我们可以更改该模块的配置,控制操作栏按钮的数量、排列顺序、展现形式等等
  2. Keyboard,它的主要功能是为键盘事件进行定制化的控制。例如,当我们需要对选中的文字进行加粗,可以点击操作栏加粗按钮实现,也可以直接通过快捷键 command+b 来达到目的。
  3. History,它主要是提供编辑器的 undo 和 redo 的功能。通过配置项,我们还可以设置多少秒内的操作合并为一个快照记录。
  4. Clipboard,它主要用于处理编辑器和外部应用之间的复制、粘贴等操作。值得注意的是,Quill 编辑器对文本格式有一定要求,粘贴到富文本的内容可能会被稍作处理。
  5. Syntax,该模块用于代码块的语法高亮。Quill 编辑器的语法高亮需要借助 highlight.js 来进行词法分析。

Parchment文档模型

Parchment 是 Quill 的文档模型,你可以把它类比为 HTML 中的 DOM 树。正如 DOM 树是由 DOM 节点构成,Parchment 则是由 Blots 构成。Quill 默认提供了几种常见的 Blots 例如:Block Blot、Inline Blot、Embed Blot。为了便于理解,你可以将其类比为 HTML 中的内联元素和块状元素。为了满足不同的格式化需求,Quill 允许我们自定义 Blot。现在我们来实现一个使文字变成斜体的功能:

let Inline = Quill.import('blots/inline');class ItalicBlot extends Inline { }
ItalicBlot.blotName = 'italic';
ItalicBlot.tagName = 'em';Quill.register(ItalicBlot);const quill = new Quill('#editor');
quill.formatText(0, 4, 'italic', true);

我们在实现一个自定义的 Blot 的时候,并不需要完全从零开始,可以继承自 Quill 默认提供的基础 Blot。一个最简单的 Blot 至少有两个最基本的静态属性,blotName 和 tagName。其中 blotName 在格式化的时候作为名字传入,而 tagName 则是创建的 HTML 元素的标签名,在本文示例中使用 em 标签实现斜体效果。

Delta数据格式

Delta 是一种用来描述文本内容和内容编辑的简单、极富表现力的格式。它是基于 JOSN 格式,易于阅读和解析。Delta 可以用来描述任何富文本文档对象,并且它没有 HTML 的复杂性和语义不明确性。我们通过一个示例来看看 Delta 结构是什么样子的。假若文本编辑器的内容为:“Gandalf the Grey”,如你所见,第一个单词 “Gandalf” 是有粗体效果的,最后一个单词 “Grey” 则是斜体效果。那么代表文本编辑器内容的 Delta 则是如下格式:

Delta = {ops: [{ insert: 'Gandalf', attributes: { bold: true } },{ insert: ' the ' },{ insert: 'Grey', attributes: { italic: true } }]
}

那如果我们想把编辑器内容由 “Gandalf the Grey” 改为 “Gandalf theWhite”又该如何操作呢?答案很简单,保持前面 12 个字符不动,插入单词“White”并使文字变蓝,删除接下来的四个字符即可。在 Quill 编辑器中调用如下代码即可实现:

const delta = new Delta().retain(12).insert('White', { color: '#00F' }).delete(4);
quill.updateContents(delta)

编辑器不显示问题

自定义上传图片需要添加自定义handlers来处理图片上传问题,添加了handlers后,编辑器不显示了,控制台还没有报错,不添加handlers还是会显示的:

解决办法

使用useMemo将quill toolbar配置包裹起来就好了

    // quill toolbarconst config = useMemo(() => {return {toolbar: {container: [[{ header: [1, 2, 3, 4, 5, false] }],['bold','italic','underline','strike','blockquote','image',],[{ list: 'ordered' },{ list: 'bullet' },{ color: [] },{ background: [] },{ align: [] },],],handlers: {image: uploadImages,},},}}, [])

自定义图片上传

有多种方式可以处理图片上传,每一种都是一个思路,1.比如监听剪切板粘贴图片的事件做处理,比如可以自定义img标签的handlers,2.或者直接监听编辑器的onChange事件,用正则匹配到图片标签后,或者监听delta变化后,将base64的图片转为file文件上传后,再将原来的img标签替换为线上链接的形式。至于哪种好,各有千秋吧

我这里选择使用第二种方式处理这些图片,原因有以下几种:

1.不用再单独处理是通过点击图片icon上传的图片还是粘贴过来的图片,统一处理delta变化处理,

2.兼容之前已经上传过的base64文章内容图片处理,如果之前已经有历史文章包含了base64的图片,也可以兼容处理了,将他们处理为链接的形式。

使用到的api有:

因为我使用的是react-quill,所以可以参考api:GitHub - zenoamaro/react-quill: A Quill component for React.

onChange:文档内容发生改变事件,可以拿到文档内容,delta数据,发生改变的原因,还有编辑器只读代理

getContents:可以获取到delta格式的文档数据内容

setContents:使用delta数据格式设置编辑器内容

还需要将base64的图片转为file然后上传到服务器中,转换函数:


export const base64ToFile = (base64, fileName = `${Math.random()}`) => {let arr = base64.split(',')console.log(arr[0])let mime = arr[0].match(/:(.*?);/)[1]let bstr = atob(arr[1])let n = bstr.lengthlet u8arr = new Uint8Array(n)while (n--) {u8arr[n] = bstr.charCodeAt(n)}console.log('mime-----', mime)return new File([u8arr], `${fileName}.${mime.split('/')[1]}`, {type: mime,})
}

需要注意

1.content和delta和editor.getHTML()获取的都是实时的文本内容,不是quill绑定的value。

const handleChangeQuill = (content, delta, source, editor) => {// content和delta和editor.getHTML()获取的都是实时的文本内容,不是quill绑定的value值.....}

2.setContents如果是粘贴图片,会导致文档指针定位回到最开始位置,需要单独处理。

3.setSelection可以设置文档指针位置,quill.setSelection(99999) 可以让指针一直处于文档末尾,但是需要根据情况处理,比如如果是用户从文档中间开始编辑的话,就设置到最底部.

4.insertEmbed可以在文档中某个位置插入新的文档节点标签,例如:

quill.insertEmbed(10, 'image', 'https://quilljs.com/images/cloud.png');

但是这种方法的前提还是需要先知道用户的光标位置。

 

监听文档变化,使用setContents更新文档内容,但是更新完之后,如果是粘贴图片会让用户的指针位置回到最开始的地方(这个问题的原因是粘贴上传图片,会导致编辑器失去焦点),这是一个问题需要解决。

解决的办法是:当文档变化的时候,让文档获取焦点

quill.focus()

所有代码: 

    const quillEdit = useRef(null)// 编辑器获取焦点,获取指针位置const [editWho, setEditWho] = useState('')const [userIndex, setUserIndex] = useState(0)// 将光标定位到用户输入的位置useEffect(() => {console.log('富文本内容改变了', editWho, userIndex)const quill = quillEdit.current.getEditor()if (editWho === 'api' && userIndex !== 0) {quill.setSelection(userIndex + 2)}}, [htmlVal])const handleChangeQuill = (content, delta, source, editor) => {// content和delta和editor.getHTML()获取的都是实时的文本内容,不是quill绑定的value值let quill = quillEdit.current.getEditor()// 如果是用户粘贴图片,需要先获取焦点,然后获取到粘贴图片的位置,等图片上传完之后,再将光标恢复quill.focus()console.log('delta_ops------', content, delta, source, editor)let delta_ops = delta.opslet quilContent = editor.getContents()setHtmlValue(content)// 获取指针位置const range = quill.getSelection()// console.log('user index------', quill.hasFocus())if (range) {if (range.length == 0 && range.index !== 0) {console.log('User cursor is at index', range.index)setUserIndex(range.index)} else {const text = quill.getText(range.index, range.length)console.log('User has highlighted: ', text)}} else {console.log('User cursor is not in editor')}setEditWho(source)if (delta_ops && delta_ops.length > 0) {quilContent.ops.map((item) => {if (item.insert) {let imgStr = item.insert.imageif (imgStr && imgStr?.includes('data:image/')) {let file = base64ToFile(imgStr)console.log('files=', file)let formData = new FormData()formData.append('file', file)// 调用文件上传接口-将二进制图片文件上传至服务器uploadFile(formData).then((res) => {// 将图片链接替换为服务器返回的图片链接item.insert.image = res.data[0]// 此方法会让用户指针回到最头部quill.setContents(quilContent)})}}})}}<ReactQuilltheme="snow"ref={quillEdit}value={htmlVal}modules={config}placeholder="请输入图文详情"onChange={handleChangeQuill}/>

最终的效果:

 

这篇关于react使用react-quill富文本编辑器自定义上传图片,添加handlers后编辑器不显示问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1014774

相关文章

linux生产者,消费者问题

pthread_cond_wait() :用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它。 pthread_cond_wait() 必须与pthread_mutex 配套使用。pthread_cond_wait()函数一进入wait状态就会自动release mutex。当其他线程通过pthread

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

2024.6.24 IDEA中文乱码问题(服务器 控制台 TOMcat)实测已解决

1.问题产生原因: 1.文件编码不一致:如果文件的编码方式与IDEA设置的编码方式不一致,就会产生乱码。确保文件和IDEA使用相同的编码,通常是UTF-8。2.IDEA设置问题:检查IDEA的全局编码设置和项目编码设置是否正确。3.终端或控制台编码问题:如果你在终端或控制台看到乱码,可能是终端的编码设置问题。确保终端使用的是支持你的文件的编码方式。 2.解决方案: 1.File -> S

JAVA读取MongoDB中的二进制图片并显示在页面上

1:Jsp页面: <td><img src="${ctx}/mongoImg/show"></td> 2:xml配置: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001

vue, 左右布局宽,可拖动改变

1:建立一个draggableMixin.js  混入的方式使用 2:代码如下draggableMixin.js  export default {data() {return {leftWidth: 330,isDragging: false,startX: 0,startWidth: 0,};},methods: {startDragging(e) {this.isDragging = tr

ONLYOFFICE 8.1 版本桌面编辑器测评

在现代办公环境中,办公软件的重要性不言而喻。从文档处理到电子表格分析,再到演示文稿制作,强大且高效的办公软件工具能够极大提升工作效率。ONLYOFFICE 作为一个功能全面且开源的办公软件套件,一直以来都受到广大用户的关注与喜爱。而其最新发布的 ONLYOFFICE 8.1 版本桌面编辑器,更是带来了诸多改进和新特性。本文将详细评测 ONLYOFFICE 8.1 版本桌面编辑器,探讨其在功能、用户

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据,优化了分类算法,支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类;一键生成危险点报告和交跨报告;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:2895356150@qq.com,资源源于网络,本介绍用于学习使用,如有侵权请您联系删除! 2.新增快速版,简洁易上手 支持快速版和专业版切换使用,快速版界面简洁,保留主