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

富文本编辑器quill.js开发(一):自定义工具栏

时间:2023-03-28 19:41:25 HTML

前言在前端开发中,富文本是一种常见的业务场景,本文是富文本框架quill.js开发介绍定义工具栏Quill。js是一个具有跨平台和跨浏览器支持的富文本编辑器。凭借其可扩展的架构和富有表现力的API,它可以完全定制以满足个性化需求。由于其模块化架构和富有表现力的API,您可以从Quill核心开始,然后根据需要自定义其模块或向此富文本编辑器添加您自己的扩展。它提供了两个用于更改编辑器外观的主题,可以使用插件或覆盖其CSS样式表中的规则进一步自定义。Quill还支持任何自定义内容和格式,因此您可以添加嵌入式幻灯片、3D模型等。此富文本编辑器的特点:由于其API驱动设计,无需像其他文本编辑器那样解析HTML或不同的DOM树;具有跨平台和浏览器支持的快速和轻量级;API是完全可定制的;内容可以表示为JSON,这样更容易处理和转换成其他格式;提供了两个主题来快速轻松地更改编辑器的外观。自定义工具栏的开发本编辑器使用了react-quill组件库,在quill.js外层包裹了一层react组件,使得开发者在react框架中使用更加友好相关链接:https://github.com/zenoamaro/…使用:从'react'导入React,{useState};从'react-quill'导入ReactQuill;导入“react-quill/dist/quill.snow.css”;函数App(){const[value,setValue]=useState('');return;}customtoolbarpasscustomtoolbarvaluecustombuttonintoolbar,可以使用iconfontsvg或者class,这里为了方便,我们直接使用textconstCustomButton=()=>find;functionApp(){const[value,setValue]=useState('');functioninsertStar(){//点击自定义图标后的回调}//自定义工具栏,useCallback重新渲染会导致显示问题constCustomToolbar=useCallback(()=>(e.persist()}>

),[]);//直接声明会导致显示问题constmodules=useMemo(()=>({toolbar:{container:'#toolbar',handlers:{insertStar:insertStar,},},}),[]);return(
)}通过这个方案,你可以创建自己的toolbarup但是也有一个缺点:quill.js的原始工具栏功能需要自己写或者从官方的例子中复制过来。现在您可以自定义工具栏并开始我们的开发之旅。本例是一个搜索替换功能的Toolbar开发,在线查看:https://d1nrnh.csb.app/首先在自定义工具栏中按照scheme添加按钮,因为上面已经有例子了,这里忽略主要结构自定义按钮的代码现在点击回调后,显示如下样式:classFindModalextendsReact.Component{render(){returnx{this.renderSearch()}{this.renderSearch()}
{'replaceall'}{'replace'}
}}你可以在外部使用状态的可见控制:visible?():null搜索栏的处理这里我们从用户输入关键字开始:当用户输入搜索关键字时,触发回调:onChangeinputtrigger_(这里我们可以添加去抖动)_:首先我们保存输入值并将搜索结果索引重置为空:this.setState({searchKey:value,indices:[],});经过quill获取所有文本格式:const{getEditor}=this.props;constquill=getEditor();consttotalText=quill.getText();解析用户输入的单词,转换成正则表达式(注意这里用户输入的意思一定要转换,避免一些关键词影响正则模式)然后不区分大小写:使用i标记,g表示全局匹配(_如果不加,只会匹配一次_):functionescapeRegExp(string){returnstring.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}constre=newRegExp(escapeRegExp(searchKey),this.state.checked?'g':'gi');之后,我们将使用totalText和re进行正则正则匹配:while((match=re.exec(totalText))!==null){//目标文本在文档中的位置letindex=match.index;//统计从开始到索引有多少特殊插入index=this.countSpecial(index,indices.length?indices[indices.length-1].index:0);//来自formatText的方法,为了突出显示它,默认选择第0个quill.formatText(index,searchKey.length,'SearchedString',true,'api');//lastrecordthesearchedcoordinatesindices.push({index});}特殊字符问题这里需要注意的是countSpecial方法的具体实现:countSpecial=(index,lastIndex)=>{const{getEditor}=这个道具;constquill=getEditor();康斯特德lta=quill.getContents();//获取前一个节点到当前节点的deltaconstrestDelta=delta.slice(lastIndex,index);constinitValue=this.specialArray.length?this.specialArray[this.specialArray.length-1]:0;constnum=restDelta.reduce((num,op)=>{if(typeofop.insert==='object'){returnnum+1;}returnnum;},initValue);这。specialArray.push(num);返回索引+数字;};它的主要功能是统计编辑器中特殊字符的个数,比如图片、表情、附件等。之所以会这样,是因为它使用了quill方法quill。得到文本();不能完全返回所有的显示,只能返回文本,和图片一样,没有实际的文本,但是有真实的占位符,像这些特殊符号只能通过deltascheme来获取是否存在,以及如果全局使用delta方案,他将无法完成搜索;比如我现在输入一首古诗,希望人长长久久,long这两个字会加粗,他显示的delta是这样的:[{insert:'Ihopepeople'},{attributes:{bold:true},insert:'longtime'},{insert:',一千里又一千里。\n'},]可以看出delta的文字是断的,任何格式都会被反汇编;所以现在我们使用的是text+delta这样的组合。搜索完成后,模式结果的坐标一旦给出相应的格式,记录当前选择的第0个搜索关键词if(indices.length){this.currentIndex=indices[0].index;//将SearchedStringActive添加到文本中,使indices[0].index到length的距离formatquill.formatText(indices[0].index,length,'SearchedStringActive',true,Emitter.sources.API);this.setState({currentPosition:0,indices,});}quillformat在上面的搜索功能中我们使用了一个API:quill.formatText这里我们就来介绍一下他。我们可以在quill.js中给他添加自定义格式。以这种SearchedString格式为例:quill.formatText(index,length,'SearchedString',true,'api');为了让它工作,我们必须首先创建文件SearchedString.ts(_可以使用js_):import{Quill}from'react-quill';constInline=Quill.import('blots/inline');classSearchedStringBlotextends内联{静态印迹名称:字符串;静态类名:字符串;statictagName:string;}SearchedStringBlot.blotName='SearchedString';SearchedStringBlot.className='ql-searched-string';SearchedStringBlot.tagName='div';导出定义aultSearchedStringBlot;入口处使用:importSearchedStringBlotfrom'./SearchedString'Quill.register(SearchedStringBlot);添加这样的格式,我们搜索调用后,搜索到的结果会有相应的类名:这里我们还需要在CSS中添加相应的样式来完成高亮功能:.ql-searched-string{//这里需要保证权重,避免搜索到的显示被背景色和字体色覆盖background-color:#ffaf0f!important;显示:内联;}搜索完成后,默认选择的是第0个,我们还需要再给一个格式:SearchedStringActive,按照上面的scheme添加这个格式,添加样式://选择的规则权限需要大于ql-searched-string规则,以及不同的颜色和背景。ql-searched-string-active{display:inline;.ql-searched-string{背景色:#337eff!重要;颜色:#fff!重要的;}}在我们的输入框末尾添加上一个和下一个功能,这里直接用图标当按钮,中间显示当前索引和总数:{currentPosition+1}/{indices.length}):null}/>点击事件点击下一个图标后,我们只需要做四步:清除上一个索引的样式索引并添加一个,判断nextone是否存在,如果不存在,则赋值0得到下一个索引,并加高亮检查下一个位置是否在窗口中,如果不存在则滚动窗口。上述数据获取源都在搜索函数中的indices数组中,标记了每个搜索结果的索引,与下一个事件相对,也就是上一个事件。它的步骤和后续步骤类似于窗口检查。点击后,我们需要判断当前高亮索引位置,依赖quill和nativepositionAPI进行调整:constscrollingContainer=quill.scrollingContainer;constbounds=quill.getBounds(index+searchKey.length,1);//bounds.top+scrollingContainer.scrollTop等于目标到顶部的距离if(bounds.top<0||bounds.top>scrollingContainer.scrollTop+scrollingContainer.offsetHeight){scrollingContainer.scrollTop=bounds.top-scrollingContainer.offsetHeight/3;}替换在搜索功能之后,我们需要添加替换功能来替换每一个,非常简单,只需要三步:删除原词,添加新词,重新搜索:quill.deleteText(this.currentIndex,searchKey.length,'user');quill.insertText(this.currentIndex,this.replaceKey,'user');这个。搜索();如果你想实现所有替换,你不需要循环通过单个替换。这会消耗更多的性能,甚至会导致延迟。对用户不友好?我目前使用的解决方案是,以相反的顺序删除:letlength=indices.length;//遍历索引尾部替换while(length--){//先删除再添加quill.deleteText(indices[length].index,oldStringLen,'user');quill.insertText(indices[length].index,newString,'user');}//this.search()结束后重新搜索;总结一下,quill有两个问题:不支持表格等格式,需要升级到2.0dev版本,但是这个版本变化很大这个仓库目前的人员说已经停止维护了,后续的更新维护是个大问题。本文从单个工具栏的开发开始介绍quill富文本编辑器的部分开发过程。目前使用quill的官方API的功能只涉及format格式。在下一篇文章中,我将继续描述表格模块和quill.js@2.x的开发。本文示例源码:点击查看参考https://juejin.cn/post/708404...系列版本富文本编辑器quill.js开发(一):自定义工具栏富文本编辑器quill。js开发(二):升级与表格功能