当前位置: 首页 > Web前端 > HTML

Quill编辑器插入自定义HTML记录

时间:2023-04-02 13:55:17 HTML

已经2020年了,饥饿的人类已经不满足于简单的文字,所以出现了花哨的各种风格的文字,但是文字还不够,我们还需要让编辑的时候,用户可以插入各种自定义消息类型,让我们发送的软文更具吸引力,于是就有了这篇文章。前言由于Quill编辑器内置了富文本过滤功能(大部分主流编辑器都会过滤富文本),开发者在配置自定义HTML模板时遇到了很多麻烦。一、Quill渲染逻辑分析要想在Quill中自定义HTML块内容,首先需要了解Quill的内部渲染流程。这里有几个需要理解的关键概念:1.DeltaDelta是Quill内部定义的一种数据格式,用来表示文档内容和文档修改操作,易于阅读,格式简单。文档内容以Delta形式维护,HTML内容与Delta可以相互转换。例如:这样一段富文本会用如下格式表示:{"ops":[{"insert":"thisisasimpletext.\\nbutwhen"},{"attributes":{"bold":true},"insert":"它是"},{"insert":"不是粗体。\\n让我试试"},{"attributes":{"italic":true},"insert":"斜体"},{"插入":"哈哈\\n"},{"属性":{"斜体":true,"粗体":true},"插入":"两者"},{"插入":"?\\n"}]}"普通文本会被定义为一个一个插入动作,每一项代表这个delta,是对文本内容的描述。同理,如果修改和删除也会产生相应的delta,然后将新生成的变化增量与原来的增量合并,生成一个新的增量。(delta中有三种操作:insert,delete,retain)前10个字符保留,后面20个字符加粗的delta如下:{"ops":[{"retain":},{"retain":,"attributes":{"bold":}}]}保留前10个字符,删除后面20个字符,如下:{"ops":[{"retain":},{"delete":}]}2.ParchmentParchment是一个管理Blot的抽象文档模型。如果将Parchment理解为一个完整的DOM树结构,那么Blot就是其中的单个节点。除了Quill中的默认,Blot还允许我们自定义,从而提供更多的扩展空间。3.BlotBlot是Parchment文档的组成部分,相当于DOM节点类型的抽象,具体的Blot实例中还有其他节点信息。全局根节点Blot是Quill内部定制的一个Scroll类型的Blot,它管理着它下面的所有Blot。Blot的实现定义可以参考这里:https://github.com/quilljs/parchment#blotsQuill中Blot的默认定义如下:常见的有TextBlot(内联普通文本)、Inline(内联normaltextwithstyles),Block(块级行,一般以段落p为单位),Break(换行符),Image(图片IMG插入),Bold(粗体文本)。一段HTML如何构建Blot?Quill会根据节点类型优先排除文本节点。如果是元素节点,则根据节点的ClassName重新判断。如果还是找不到匹配的BlotName,就会默认匹配下面的映射关系,找到对应的BlotClass。4.Delta的实际意义既然已经有Blots可以代表我们的内容结构,为什么还需要Delta呢?Delta本身只是一个内容数据的维护,也就是说HTML的更新,无论是用户输入还是API操作,都会同步更新到Delta,如果不使用Delta作为HTML的数据源,那么维护一份Delta数据的意义在哪里?如果HTML=>Delta,但没有Delta=>HTML,那么维护delta的副本有什么意义呢?1、Delta生成的HTML其实是存在的,但是应用场景仅限于初始化文档的时候。Quill会对传入的初始化HTML字符串进行解析处理,生成对应的Delta,然后通过applyDelta与页面Echo生成DOM节点。2、看到这里你可能不满意。为什么一定要经过这一步?初始化的时候,只要设置一个字符串document.getElementById('container').innerHTML=val。是的,你可以,但是Delta的存在让用户的文档更细粒度,更容易维护,更可追溯。如果A和B同时在编辑一个文档,A在第二行删除了10个字符,那么不需要更新整个文档的内容,只需要提交一个action操作来同步自己的行为,并且B只需要处理完冲突Merge即可。虽然Delta的维护让逻辑复杂了很多,但它的存在也让文档的扩展性更强。五、编辑器渲染和更新过程修改内容有以下三种方式:1、初始化编辑器内容:调用quill.pasteHTML进行初始化,HTML过滤解析后显示在编辑框中。2.InputEvent:用户输入和编辑操作被MutationObserver监听和处理,更新delta。3、API调用:调用内部提供的API,传递修改方法,然后调用全局Scroll实例的方法进行修改。2、插入自定义HTML块随着文章内容越来越多样化,文章中出现了插入地图、音乐播放器、广告面板等需求,因此我们需要为富文本编辑器扩展更多的功能。但同时也要做好xss防护攻击。根据第一部分,我们需要插入一个自定义的HTML块,同时Quill可以识别它。你一定想到了,我们需要定制一个Blot。通过定义Blot方法,Quill可以在初始化时识别我们的HTML块显示,同时在插入HTML块时不会被Quill过滤。注册Blot的方法如下:exportdefaultfunction(Quill){//源码中importBlockEmbedconstBlockEmbed=Quill.import('blots/block/embed');//定义一种新的印迹类AppPanelEmbedextendsBlockEmbed{staticcreate(value){constnode=super.create(value);node.setAttribute('contenteditable','false');node.setAttribute('宽度','100%');//设置自定义htmlnode.innerHTML=this.transformValue(value)returnnode;}statictransformValue(value){lethandleArr=value.split('\n')handleArr=handleArr.map(e=>e.replace(/^[\s]+/,'').replace(/[\s]+$/,''))returnhandleArr.join('')}//返回节点本身的值来撤销操作staticvalue(node){returnnode.innerHTML}}//blotNameAppPanelEmbed.blotName='AppPanelEmbed';//类名将用于匹配印迹名称AppPanelEmbed.className='embed-innerApp';//标签类型自定义AppPanelEmbed.tagName='div';Quill.register(AppPanelEmbed,true);}接下来你只需要这样调用就可以在编辑器中插入一个自定义的HTML块:quill。insertEmbed(quill.getSelection().index||0,'AppPanelEmbed',`自定义面板标题

自定义面板内容
页脚
`);参数传递格式要求如下:insertEmbed(index:Number,type:String,value:any,source:String\='api'):delta这里只是这个是一个简单的例子。如果想丰富自定义Blot的功能,可以参考:https://github.com/quilljs/parchment#blots由于释放了contenteditable属性,为了防止xss攻击,我们需要对这个属性Filter处理,这里是xss模块处理的例子:handleWithXss(content){constoptions={whiteList:{...div:['class','style','data-id','contenteditable'],.。alue,isWhiteAttr)=>{//div的contenteditable处理if(isWhiteAttr&&tag==='div'&&name==='contenteditable'){return'contenteditable="false"';}},}//自定义规则constmyxss=newxss.FilterXSS(options)returnmyxss.process(content)}到此大功告成~感谢观看~