拓冰建站拓冰建站
首页 / 资讯中心 / 正文

layui layedit富文本增强:字体颜色、字号、背景色扩展实现

简介这是一套面向前端开发者的 layui 富文本编辑器 layedit.js 功能增强资源重点解决字体大小、字体颜色与背景颜色的自定义设置需求适合需要在内容编辑场景中快速集成或改造 layedit 的读者。资源包共 126 个文件压缩后约 849KB其中包含 75 个 gif 图标、29 个 js 脚本与 6 个 css 样式表另有 4 个 html 示例页面、3 个 png 图片及多种字体格式文件便于直接对照调试和二次开发。该资源可帮助搭建完整的 layedit 工具栏配置覆盖字体类型、字号缩放、前景色与背景色切换同时可作为表格插入、图片批量上传、超链接与视频插入、全屏编辑、段落与锚点设置等功能的样式与逻辑参考。目前已有 260 人学习下载对希望以轻量方式完善 layui 富文本体验、减少重复开发的开发者而言是一份实用且便于查阅的素材。 做后台管理系统做久了你会发现富文本这块是最容易扯皮的。我用 layui 做过好几个项目每次都逃不过同一个需求默认的 layedit.js 富文本编辑器只有加粗、斜体、下划线、超链接这几个基础按钮用户一上来就问“字体大小在哪调字体颜色怎么改背景色能不能标一下”这几个功能默认根本没做但业务上又绕不开。这篇文章把我踩过的坑、最后稳定的实现方案完整写一遍给正在用 layui 做后台的开发者一点参考。内容会从 layedit 的底层原理讲起再给一套不碰源码的扩展方案最后附上我实际遇到过的兼容性问题和解决记录。1. 先弄清楚 layedit 的底细才好动手改1.1 layedit 默认到底缺了什么layui 自身带的 layedit.js 是一个轻量级富文本外观上跟 layui 风格统一集成简单一个layedit.build()就能把编辑器挂到 textarea 上。但它本质上只是把页面里的 textarea 藏起来换成一个 iframeiframe 内部的 body 设置了contenteditabletrue用户编辑的其实是 iframe 里的内容。所以后续所有字体操作都要在 iframe 内部文档上做而不是操作父页面的 DOM。默认工具栏我在代码里核对过大概只有这些strong加粗italic斜体underline下划线del删除线|分隔符link添加链接unlink取消链接face表情一眼就能看出来字体大小、字体颜色、背景颜色这三个编辑最常用的工具官方根本没有封装。网上搜这个问题的人特别多说明这不是我一个人的需求。要解决它先得明白 layedit 是怎么处理文本格式的。1.2 改字体颜色背景色靠的是哪几个底层命令layedit 的所有格式化动作底层走的都是浏览器内置的document.execCommand。我没去翻源码前也不知道它这么“原始”后来在控制台试了一下发现编辑器内所有加粗、斜体操作都会落到这条老命令上。execCommand 是浏览器提供给可编辑区域的一条命令通道传入不同的命令名和参数就能修改选区内的内容。跟标题需求直接相关的三条命令是fontSize设置字号但参数只支持 1 到 7 的整数对应 HTML 里font size1到font size7不是像素值foreColor设置字体颜色参数是色值比如#ff0000hiliteColor设置文字背景高亮色也就是我们常说的“荧光笔”效果参数同样是色值知道这三个命令就等于拿到了操作编辑器内部内容的钥匙。但实际落地的坑在于命令是能调用但浏览器之间对命令的解析有差异而且怎么让用户方便地选色、选字号也得自己想办法。这是我在实现前没预料到的后面会一个个展开。2. 两种扩展方案我推荐你用第二种2.1 改源码短期爽升级苦网上很多教程的做法是直接改layedit.js源文件把按钮定义和点击事件写死在源码里。这个方案不是不行但有个明显的后遗症以后 layui 版本升级源文件一覆盖你改的东西全没了。而且 layedit.js 源码压缩过在里面找位置、加代码改起来很痛苦出了问题也不容易排查。我自己第一次做的时候为了省事改过一版加了个字体颜色按钮改了大概十几行代码。当时能跑但后面 layui 升级到新版本覆盖了这个文件客户反馈颜色按钮消失我排查了半天才发现是源码被替换了。从那以后我不再建议改源码除非你能保证以后永远不升级。2.2 工具栏接管不碰源码也能加按钮更稳的思路是让 layedit 正常初始化然后我自己往它的工具栏区域里追加自定义控件。layedit 在初始化后工具栏按钮会渲染在编辑器容器上方的.layui-layedit-tool这个容器里里面的按钮都是类似i lay-filterbold classlayui-icon layui-icon-bold/i这样带lay-filter属性的图标。我们完全可以用 jQuery 在这个工具栏里插入自定义按钮、下拉框或颜色选择器然后绑定自己的事件。这样做有几个好处不动源码升级 layui 不影响现有功能自定义逻辑独立出错时只需要排查自己那部分代码交互可以做得更顺手比如用 input typecolor 当取色器或加一组预设色板我在实际项目中一直用这个方案稳定跑了一年多没出过问题。下面的实操就是基于这个思路写的。3. 实操全流程字号、颜色、背景色接入3.1 初始化与自定义工具栏注入先按正常方式初始化 layedittextarea 可以自己定义 id比如idcontentvar layeditIndex layedit.build(content, { tool: [strong, italic, underline, del, |, link, unlink, face], height: 300 });初始化完成后把自定义控件塞进工具栏。工具栏容器可以用layui生成的结构去定位更简单的方式是等编辑器渲染后通过类名去查找var $toolBar $(.layui-layedit-tool).eq(0);然后追加自定义控件。这里根据我自己的排版习惯在工具栏后面依次追加字号下拉框、颜色选择器和背景色选择器。代码示例如下div idcustomToolbar styledisplay:inline-block; vertical-align:middle; padding-left:6px; select idfontSizeSel lay-ignore styleheight:26px; width:72px; font-size:12px; option value字号/option option value1212px/option option value1414px/option option value1616px/option option value1818px/option option value2020px/option option value2424px/option option value3232px/option option value4848px/option /select input typecolor idfontColorPicker title字体颜色 stylewidth:30px; height:26px; vertical-align:middle; input typecolor idbgColorPicker title背景颜色 stylewidth:30px; height:26px; vertical-align:middle; /div注意 select 上加lay-ignore防止 layui 的 form 模块把原生下拉重新渲染否则取值麻烦。input typecolor 是浏览器原生取色器安卓和手机端上体验稍弱但后台场景大多是电脑端够用。追加的 HTML 不要放在页面里而是通过 JS 插入这样可以保证编辑器动态创建时也能正确对位$($toolBar).append($(#customToolbar));3.2 字号下拉的实现细节字号这块最大的坑是fontSize命令不支持像素值只认 1 到 7。如果你直接执行document.execCommand(fontSize, false, 12)浏览器不认 12 这个数字只有 1~7 有效。我一开始就掉进这个坑里后来换了个稳妥的做法先用fontSize命令生成font size7再在编辑器内部把font[size]统一替换成带像素值的span stylefont-size:48px这样既能保留选区位置又能得到像素级控制。具体实现代码如下var frame layedit.getFrame(layeditIndex); var doc frame.contentDocument; $(#fontSizeSel).on(change, function() { var val parseInt(this.value, 10); if (!val) return; doc.execCommand(fontSize, false, 7); // 把编辑器内所有 font[size] 统一替换为内联样式 var fontList doc.querySelectorAll(font[size]); fontList.forEach(function(font) { var oldSize font.getAttribute(size); var px oldSize 7 ? 48 : oldSize 6 ? 32 : oldSize 5 ? 24 : 16; font.removeAttribute(size); font.style.fontSize px px; // 孤立的 font 标签可以换成 span语义更干净 var span doc.createElement(span); span.style.fontSize px px; span.innerHTML font.innerHTML; font.parentNode.replaceChild(span, font); }); });为什么固定用 size 7因为它的字号最大替换时不会因为浏览器默认字号映射造成偏差。你也可以按 1~7 分别映射成你想要的像素值上面代码里做了个简单的映射表实际项目里你可以按产品需求调整成 10px~48px 任意数值。这里还有个小技巧执行完替换之后旧的font会被替换成span选区可能丢失。所以如果要在手机上用建议在 change 事件触发前保存当前选区替换后再恢复选区保证连续设置字号时不会中断。桌面端浏览器一般没事但这是兼容性细节我在后面会再提到。3.3 颜色选择器与背景色命令字体颜色和背景高亮的实现思路完全一致只是命令不同。字体颜色用foreColor背景颜色用hiliteColor。绑定 input 事件取色器一变立刻应用$(#fontColorPicker).on(input, function() { var color this.value; doc.execCommand(foreColor, false, color); }); $(#bgColorPicker).on(input, function() { var color this.value; doc.execCommand(hiliteColor, false, color); });如果项目只支持 Chrome、Edge、Firefox这段代码已经可以用了。但如果是给客户做的系统客户用 Safari 的情况你没法控制Safari 对hiliteColor的支持不太好会出现“命令执行了但背景色没变”的问题。我的兼容方案是做一个能力检测如果不支持就退回backColorfunction applyBgColor(color) { var support false; try { doc.execCommand(hiliteColor, false, #000000); support true; } catch (e) { support false; } if (support) { doc.execCommand(hiliteColor, false, color); } else { doc.execCommand(backColor, false, color); } }backColor和hiliteColor的区别是backColor在部分浏览器里会修改整个块级区域的背景色而不只是选中的那行文字。真遇到这种情况我建议别忘了状态检查——如果 Safari 上试出来背景色没有按预期输出说明命令不可靠就得用更底层的方式手动包裹span具体思路我在后面的排坑章节细说。3.4 失焦问题与选区恢复这是最隐蔽的一个坑。用 input typecolor 选择颜色时点击取色器按钮的一瞬间编辑器 iframe 会失去焦点原来选中的文字选区就没了。没有选区execCommand就不知道要改谁结果就是颜色根本没应用上。第一次遇到这个问题我检查了半天代码命令参数完全正确但就是没效果。最后发现是选区丢失。解决办法是在打开取色器之前记录当前的 selection 和 range等取色完成后再恢复var lastRange null; $(#fontColorPicker).on(mousedown, function(e) { e.preventDefault(); // 阻止默认行为保住焦点 var sel doc.getSelection(); if (sel sel.rangeCount 0) { lastRange sel.getRangeAt(0).cloneRange(); } }); $(#fontColorPicker).on(input, function() { if (lastRange) { var sel doc.getSelection(); sel.removeAllRanges(); sel.addRange(lastRange); } var color this.value; doc.execCommand(foreColor, false, color); });mousedown 里 preventDefault 是为了阻止取色器抢焦点。注意顺序先阻止默认再保存 range这样编辑器焦点还没丢range 还在。取色器 input 事件触发时再恢复 range最后执行命令。字体大小下拉和背景色选择器也要做同样处理否则它们同样会触发失焦问题。3.5 内容同步是最后一步编辑器里显示的是 iframe 内部的东西textarea 里保存的其实是编辑器的初始值。提交表单时如果不做同步用户写的全部内容都会丢。layedit 提供了一个同步方法layedit.sync(layeditIndex);建议在表单提交事件里先执行同步form.on(submit(*), function() { layedit.sync(layeditIndex); // 继续走提交逻辑 return true; });如果你是在 AJAX 提交前取内容也可以直接用layedit.getContent(layeditIndex)这个方法本身就做了同步并返回 HTML 字符串比 sync 再手动拿 textarea 值更省事。4. 踩坑记录与排查速查表4.1 Safari 下背景色失灵的手动包裹方案前文说了hiliteColor在 Safari 上不可用backColor又会把整个块变成背景色效果跟荧光笔完全不同。如果你必须兼容 Safari我测试过的最可靠方案是手动操作 Range 对象给选中内容包裹spanfunction applyBgColorSafari(color) { var sel doc.getSelection(); if (!sel.rangeCount) return; var range sel.getRangeAt(0); var span doc.createElement(span); span.style.backgroundColor color; try { range.surroundContents(span); } catch (err) { // 选区跨多个块级元素时会报错将选区内容包到 span 里 var frag range.extractContents(); span.appendChild(frag); range.insertNode(span); } }这里要注意surroundContents有个限制当选区包含多个不完整的段落节点时会抛异常所以 catch 里用了先 extractContents 再 insertNode 的迂回方案。这套代码在 Safari 和桌面 Chrome 上都验证过能稳定给选中文字加背景色。4.2 提交后内容里全是 font size 标签如果你偷懒直接用fontSize命令不做后续替换提交到后台的内容会长这样font size7标题文字/fontfont标签虽然浏览器还能识别但维护性很差而且size属性和像素之间没有稳定的换算关系。我在代码里用的是把font size替换成span stylefont-size:xxpx的方案提交出去的内容干净统一后续做导出 PDF、Word 时也更容易适配。如果你想要不同字号更精确映射表可以自己定义完全看你业务需要。4.3 工具栏按钮状态不同步layedit 内置的加粗、斜体按钮点击后会有个.layui-icon-active高亮状态但我自定义的颜色和字号控件做不到自动回显。比如用户把字号改成 16px光标移到别处字号下拉还停留在默认位置选中了一段 20px 的文字下拉也不会有联动。这个在纯 layedit 框架下基本没法完美解决需要监听 iframe 的 keyup 和 mouseup 事件然后用doc.queryCommandValue(fontSize)去回填状态。我做过一版但判断逻辑复杂且不完美最后只在 keyup 时简单刷新字号下拉变色状态直接放弃。后台场景下这个影响不大文章写完了自然知道字号效果。4.4 常见问题速查表问题现象可能原因解决办法点颜色按钮没反应iframe 失焦选区丢失mousedown 里 preventDefault 并保存 range背景色点了没变化Safari 不支持 hiliteColor改用 backColor 或手动包裹 span字号执行后没效果fontSize 传了像素值不是 1~7先传 7 再统一替换为 span 的像素样式提交后内容丢失没有同步编辑器内容提交前调用 layedit.sync(index)追加的控件被换行工具栏宽度不够或容器布局问题用 display:inline-block 并设置 lay-ignore取色器颜色带透明度input typecolor 是纯色值格式换成预设色板自定义颜色面板4.5 如果不想自己造轮子换编辑器也值得考虑如果你正在做一个新项目layedit 不是唯一选择。layui 官方后来也意识到富文本这块比较弱推荐过集成第三方编辑器。我自己的建议是老项目维护用我这套扩展没问题新项目或者对编辑体验要求高、需要上传图片、需要表格、需要粘贴 Word 格式保真的场景可以考虑 wangEditor、Tinymce 这类专业编辑器它们本身就有完整的字体颜色、背景色、字号联动方案比自己补 layedit 省心得多。不过这是看需求定的有些项目风格统一优先layedit 也还能打。最后再分享一点个人体会。这套扩展方案我前后花了差不多一个下午才完全调通核心花销不在代码而在排查那些“命令没效果”的隐形问题。其实每个问题回头看看都挺简单的但当时不自查的话很容易陷入改源码、加 console、反复初始化编辑器的死循环。现在我把这些记录整理成文也是希望后来者别再掉进同一个坑。如果按照上面的步骤操作后仍有个别浏览器行为不一致建议优先检查一下是否真的是选区丢失十有八九问题出在那里。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门