今天分享下”Quill编辑器操作实例详解“这篇文章,文中根据实例编码详细介绍,或许对大家的编程之路有着一定的参考空间与使用价值,需要的朋友接下来跟着云南仟龙Mark一起学习一下吧。

一转眼早已2020年,难耐的人们不会再能够满足于简易的文本,因此拥有花哨的带上各种各样款式的文本,殊不知有文本还不够,大家还必须让使用者在小编的情况下,可以插进各种各样自定义信息种类,使我们传出去的推广软文更为漂亮,因而拥有本文。

序言

因为Quill在线编辑器内置的富文本过虑(绝大多数流行在线编辑器都是会对富文本开展过虑解决),造成开发人员要想配备自定义HTML模板时,碰到了许多不便。

一、Quill3D渲染逻辑性剖析

为了更好地自定义Quill中的HTML块内容,最先必须掌握Quill內部的3D渲染步骤,这儿几个主要的定义必须掌握:

1、Delta

Delta是Quill內部界定的一个数据类型,用以表明文档内容及其文档改动实际操作,最易读且文件格式简易,根据Delta的方式来维护保养文档内容,HTML内容和Delta二者还可以互相转换。

举个事例:

这样一段富文本会被表示成以下的格式:

1

2

3

4

5

6

7

8

9

10

​​{ ​​

​​"ops":[ ​​

​​{“insert”:"this is a simple text.\nbut when "}, ​​

​​{“attributes”:{“bold”:true},“insert”:"it is "}, ​​

​​{“insert”:"not bold.\nlet me try "}, ​​

​​{“attributes”:{“italic”:true},“insert”:"italic "}, ​​

​​{“insert”:"haha\nwhat about "}, {“attributes”: ​​

​​{“italic”:true,“bold”:true},“insert”:“both”}, ​​

​​{“insert”:" ?\n"} ] ​​

​​}"​​

普通的文本会被定义成一个个的insert动作,每一项代表这一个delta,都是对文本内容的描述。

类似的,如果修改和删除也会生成对应的delta,之后会将新生成的change delta,与原有的delta进行合并操作,生成新的delta。(delta中一共包含三种操作:insert、delete、retain)

保留前10个字符,对后续的20个字符进行加粗操作的delta如下:

1

2

3

4

5

6

​​{​​

​​"ops": [​​

​​{ “retain”: },​​

​​{ “retain”: , “attributes”: { “bold”: } }​​

​​]​​

​​}​​

保留前10个字符,对后续的20个字符进行删除操作如下:

1

2

3

4

5

6

​​{​​

​​"ops": [​​

​​{ “retain”: },​​

​​{ “delete”: }​​

​​]​​

​​}​​

2、Parchment

Parchment是抽象的文档模型,对Blot进行管理。

将Parchment理解成完整的DOM树结构的话,那么Blot就是其中一个个单一的节点。而Blot去了Quill中默认的以外,还允许我们进行自定义,给了更大的扩展空间。

3、Blot

Blot是Parchment文档的组成部分,相当于对DOM节点类型的抽象,而一个具体的Blot实例里仍有其他的节点信息。

全局的根节点Blot是由Quill内部自定义的Scroll类型Blot,管理其下面的所有Blot。

对于Blot的实现定义可以参照这里: https://github.com/quilljs/parchment#blots

Quill中默认定义的Blot如下:

这其中常见的包括TextBlot(行内普通文本)、Inline(行内携带样式的普通文本)、Block(块级行,一般以段落p为单位)、Break(换行)、Image(图片IMG插入)、Bold(加粗文本)。

而一段HTML如何构建出Blot?Quill中会根据节点类型优先排除文本节点,如果是元素节点会根据节点的ClassName进行再次判断,如果仍然无法找到匹配的BlotName,则默认匹配以下的映射关系,来找到对应的BlotClass。

4、Delta的实际意义

既然已经有Blot可以来表示我们的内容结构了,为什么还需要Delta?Delta本身只是一份内容数据的维护,也就是说HTML的更新,无论是用户输入,还是API操作,都会同步更新到Delta中,而Delta如果不作为HTML的数据源的话,那么维护一份Delta数据的意义又在哪里?

如果HTML => Delta,而不存在Delta=>HTML,那么不停地去维护一份delta的意义是什么?

1、由Delta生成HTML其实是存在的,只不过应用场景只限于初始化文档的时候,Quill会对传入的初始化HTML字符串进行解析处理,生成对应的Delta,其次通过applyDelta的方式,生成DOM节点回显与页面中。

2、看到这里你可能还不满意,为啥非要走这一步流程,初始化的时候直接一段字符串document.getElementById(‘container’).innerHTML = val不行吗,是的,可以,但是Delta的存在让用户的文档变得粒度更细小,变得易维护,变得可追溯。假如A和B同时编辑着一份文档,A删除了第二行的10个字符,不需要将文档内容全量更新,只需要提交action操作,同步自己的行为,而B这边也只需要进行冲突处理后merge即可。虽然Delta的维护让逻辑变得复杂了不少,但它的存在也让文档有了更多扩展的可能。

5、编辑器渲染与更新流程

对于内容的修改一共有以下3种方式:

1、初始化编辑器内容:初始化调用quill.pasteHTML,经过HTML过滤和解析回显到编辑框中。

2、Input Event:用户输入和编辑操作,通过MutationObserver监听处理,更新delta。

3、API调用:调用内部提供API,通过modify方法,而后调用全局Scroll实例的方法去修改。

二、插入自定义HTML块

由于文章内容越来越多样化,在文章插入地图、音乐播放器、广告面板等需求的存在,让我们需要对富文本编辑器扩展出更多的功能。但是同时也要做好xss防护。

按照第一部分的讲述,我们需要插入一个自定义HTML块,同时又要Quill能够识别,聪明的你一定想到了,我们需要自定义一个Blot。通过定义好Blot的方式,让Quill在初始化的时候能够识别我们的HTML块展示,同时也让我们在插入HTML块的时候不会被Quill进行脏HTML过滤。

注册Blot方法如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

​​export default function (Quill) {​​

​​// 引入源码中的BlockEmbed​​

​​const BlockEmbed = Quill.import(‘blots/block/embed’);​​

​​// 定义新的blot类型​​

​​class AppPanelEmbed extends BlockEmbed {​​

​​static create(value) {​​

​​const node = super.create(value);​​

​​node.setAttribute(‘contenteditable’, ‘false’);​​

​​node.setAttribute(‘width’, ‘100%’);​​

​​// 设置自定义html​​

​​node.innerHTML =​​http://www.qlyl1688.com/products/ycxsyc.html​​ this.transformValue(value)​​

​​return node;​​

​​}​​

​​static transformValue(value) {​​

​​let handleArr = value.split(’\n’)​​

​​handleArr = handleArr.map(e => e.replace(/1+/, ‘’)​​

​​.replace(/[\s]+$/, ‘’))​​

​​return handleArr.join(’’)​​

​​}​​

​​// 返回节点自身的value值 用于撤销操作​​

​​static value(node) {​​

​​return node.innerHTML​​

​​}​​

​​}​​

​​// blotName​​

​​AppPanelEmbed.blotName = ‘AppPanelEmbed’;​​

​​// class名将用于匹配blot名称​​

​​AppPanelEmbed.className = ‘embed-innerApp’;​​

​​// 标签类型自定义​​

​​AppPanelEmbed.tagName = ‘div’;​​

​​Quill.register(AppPanelEmbed, true);​​

​​}​​

接下来你只需要这样调用,便可以在编辑器中插入自定义的HTML块:

1

2

3

4

5

6

7

8

9

10

11

​​quill.insertEmbed(quill.getSelection().index || 0, ‘AppPanelEmbed’, `​​

​​<​​​​div​​ ​​class​​​​=​​​​"app_card_header"​​​​> ​​

​​自定义面板标题​​

​​</​​​​div​​​​>​​

​​<​​​​div​​ ​​class​​​​=​​​​"app_card_content"​​​​> ​​

​​自定义面板内容​​

​​</​​​​div​​​​>​​

​​<​​​​div​​ ​​class​​​​=​​​​"app_card_footer"​​​​> ​​

​​footer​​

​​</​​​​div​​​​>​​

​​`);​​

传参格式要求如下:

1

​​insertEmbed(index: Number, type: String, value: any, source: String = ‘api’): Delta​​

这里仅仅这是个简单的示例,如果想丰富自定义Blot的功能,可以参照: https://github.com/quilljs/parchment#blots

由于contenteditable属性放开,为了防止造成xss进攻,所以需要我们对该属性做特殊的过滤处理,这里以xss模块处理为例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

​​handleWithXss(content) {​​

​​const options = {​​

​​whiteList: {​​

​​…​​

​​div: [‘class’, ‘style’, ‘data-id’,‘contenteditable’],​​

​​…​​

​​},​​

​​css: {​​

​​whiteList: {​​

​​color: true,​​

​​’background-color’: true,​​

​​’max-width’: true,​​

​​},​​

​​},​​

​​stripIgnoreTag: true,​​

​​onTagAttr: (tag, name, value, isWhiteAttr) => {​​

​​// 针对div的contenteditable 处理​​

​​if (isWhiteAttr && tag === ‘div’ && name === ‘contenteditable’) {​​

​​return ‘contenteditable=“false”’;​​

​​}​​

​​},​​

​​} // 自定义规则​​

​​const myxss = new xss.FilterXSS(options)​​

​​return myxss.process(content)​​

​​}​​

今天的文章就分享到这啦,内容转自脚本之家,下篇文章再见。


  1. \s ↩︎

Quill编辑器操作实例详解相关推荐

  1. mysql通过集合查询_MySQL使用集合函数进行查询操作实例详解

    本文实例讲述了MySQL使用集合函数进行查询操作.分享给大家供大家参考,具体如下: COUNT函数 SELECT COUNT(*) AS cust_num from customers; SELECT ...

  2. python代码覆盖率测试_unittest+coverage单元测试代码覆盖操作实例详解_python

    这篇文章主要为大家详细介绍了unittest+coverage单元测试代码覆盖操作的实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 基于上一篇文章,这篇文章是关于使用coverage来实现代码 ...

  3. python实现文本编辑器_Python实现文本编辑器功能实例详解

    这篇文章主要介绍了Python实现的文本编辑器功能,结合实例形式详细分析了基于wxpython实现文本编辑器所需的功能及相关实现技巧,需要的朋友可以参考下 本文实例讲述了Python实现的文本编辑器功 ...

  4. android代码删除wifi,Android Wifi的forget()操作实例详解_Android_脚本之家

    Android  Wifi的forget()操作实例详解 我们在处理某个Wifi连接时,有时会需要忘掉当前连接的密码信息.执行这项操作,我们需要调用WifiManager::forget()函数: / ...

  5. php gearman 定时任务,php使用gearman进行任务分发操作实例详解

    php使用gearman进行任务分发操作实例详解,创建一个,客户端,操作,实例,回调 php使用gearman进行任务分发操作实例详解 易采站长站,站长之家为您整理了php使用gearman进行任务分 ...

  6. 微信小程序php返回数组,微信小程序 数组(增,删,改,查)等操作实例详解...

    微信小程序 数组(增,删,改,查)等操作 最近在做一个小程序的demo.由于不向后台请求数据,所以就涉及到对本地数据的操作,也遇到了一些坑,本文就以数组的增删改查为例,给新手分享一些经验. 首先这是原 ...

  7. mysql resulttype map_Mybatis中的resultType和resultMap查询操作实例详解

    resultType和resultMap只能有一个成立,resultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用,resultMap解决复杂查询是的映射问题.比 ...

  8. python爬虫之Scrapy框架原理及操作实例详解、股票数据Scrapy爬虫

    爬虫框架 -scrapy.pyspider.crawley等 Scrapy框架 1.scrapy框架介绍 -https://doc.scrapy.org/en/latest/ -http://scra ...

  9. pythonjson实例_python对json的相关操作实例详解

    本文实例分析了python对json的相关操作.分享给大家供大家参考,具体如下: 什么是json: JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人 ...

最新文章

  1. java多线程消息队列_java多线程消息队列的实现
  2. linux定时器(crontab)实例
  3. PHP与base64
  4. 原型图Mockplus:怎样使用图片裁切功能
  5. CVPR2014: DeepID解读
  6. 关于Vmware ESX 4.1添加第二个Servier Console 却无法添加网关的解决方法
  7. java system datetime_Java8新特性时间日期库DateTime API及示例
  8. 系统学习深度学习(二十二)--CNN经典模型总结
  9. 我们一起踩过的坑----react(antd)(二)
  10. 【UVALive - 7344】Numbered Cards【数位DP+状压DP】
  11. 多目标跟踪算法SOART
  12. 坐标系的另一种表达形式,EPSG是什么?
  13. 请和我一起学习机器学习算法(高斯混合聚类)
  14. c语言多态性编码图形,C和C++经典著作 C专家编程Expert C Programming Deep C Secrets pdf...
  15. 【Win 10 应用开发】MIDI 音乐合成——乐理篇
  16. QT C2220: 警告被视为错误 - 没有生成“object”文件
  17. b站评论功能(一级评论到n级)
  18. 如何在PowerPoint中更改文本的大小写
  19. 如何在vim快速删除全部内容
  20. [转] 整理一下SQLSERVER的排序规则

热门文章

  1. OSError: [WinError 1455] 页面文件太小,无法完成操作。 Error loading “C:\Users\rg\.conda\envs\pytorch\lib\site
  2. Dashboard设计
  3. python3.6安装包下载_Python 3.6.6安装教程(附安装包) | 我爱分享网
  4. #内存泄露# #valgrind# valgrind使用
  5. Java在线考试系统(含源码)
  6. 微商和微信营销遇到的问题 转载
  7. sideeffects没配置css也还在,webpack4踩坑配置之sideEffects, 打包文件中没有css文件
  8. dump会卡住mysql吗_使用MySQL MySqldump命令导出数据时的注意事项
  9. 时钟MUX电路结构的时序约束方法分析
  10. Torch深度学习的60分钟教程(翻译)