如何让Quill syntax模块对全文本而非仅代码块应用语法高亮?
解决方案:在react-quill中全局高亮自定义合并字段
核心问题解决思路
Quill的syntax模块本身就是为代码块设计的,无法直接全局应用。要实现任意位置的字段高亮,得通过自定义Inline Blot扩展Quill的内容模型,手动匹配并包裹目标字段,而非依赖syntax模块。
步骤1:创建自定义高亮Blot
Blot是Quill的内容基本单元,我们可以定义一个inline类型的Blot来承载高亮样式:
import Quill from 'quill'; const Inline = Quill.import('blots/inline'); class MergeFieldBlot extends Inline { static blotName = 'merge-field'; static tagName = 'span'; static className = 'merge-field-highlight'; static create(value) { const node = super.create(value); node.classList.add(this.className); // 可存储字段类型,方便后续区分格式 if (value.type) { node.dataset.type = value.type; } return node; } static formats(node) { return { type: node.dataset.type }; } } // 注册自定义Blot Quill.register(MergeFieldBlot);
对应的CSS样式:
.merge-field-highlight { background-color: #fff3cd; padding: 2px 4px; border-radius: 3px; }
步骤2:实现文本扫描与自动包裹逻辑
监听Quill的text-change事件,在内容变化时扫描文本中的目标字段,用自定义Blot包裹:
import ReactQuill from 'react-quill'; import 'react-quill/dist/quill.snow.css'; const MyEditor = () => { const quillRef = React.useRef(null); // 扫描并包裹合并字段 const highlightMergeFields = () => { const quill = quillRef.current?.getEditor(); if (!quill) return; const range = quill.getSelection(); quill.disable(); // 避免扫描过程中触发多次text-change // 匹配两种格式的正则:<<[内容]>> 和 [[内容]] const regex = /(<<\[([^\]]*)\]>>|\[\[([^\]]*)\]\])/g; const content = quill.getText(); let match; while ((match = regex.exec(content)) !== null) { const startIndex = match.index; const endIndex = startIndex + match[0].length; // 检查当前位置是否已被高亮包裹,避免重复处理 const [blot] = quill.getLine(startIndex); const offset = startIndex - blot.offset(); const node = blot.domNode.childNodes[offset]; if (node?.classList?.contains('merge-field-highlight')) continue; // 应用自定义格式 quill.formatText(startIndex, match[0].length, 'merge-field', { type: match[0].startsWith('<<') ? 'aspose' : 'manual' }); } quill.enable(); if (range) quill.setSelection(range); // 恢复光标位置 }; return ( <ReactQuill ref={quillRef} onChange={(_, delta, source) => { // 仅在用户输入时触发高亮,避免程序修改内容时重复执行 if (source === 'user') { setTimeout(highlightMergeFields, 0); // 延迟执行确保内容已更新 } }} modules={{ toolbar: [/* 你的工具栏配置 */] // 无需再配置syntax模块 }} /> ); }; export default MyEditor;
步骤3:处理编辑边界情况
- 自定义Blot继承自Inline,默认会在用户编辑高亮字段内容时保持包裹状态,除非删除整个字段。
- 若需要在字段被破坏时自动取消高亮,可以在
text-change事件中额外检查字段完整性,当正则匹配不成立时,移除merge-field格式。
次要问题解答
高亮标签不在onChange输出的原因:
Quill的syntax模块在代码块中是将高亮作为代码块的内部格式处理,不会输出额外HTML标签——代码块内容以纯文本+语法类形式存储,onChange输出的是<pre><code>...</code></pre>,高亮通过CSS类实现,不会嵌入标签。脱离代码块后高亮标签是否会进入输出:
是的。撤销代码块后,syntax模块的高亮会被转换为带highlight.js类的普通HTML span标签,这些标签会出现在onChange的HTML输出中。而我们自定义的Blot,按上述配置后,onChange输出会包含<span class="merge-field-highlight">...</span>,可根据需求在输出时选择保留、替换或移除这些标签。
内容的提问来源于stack exchange,提问作者Grank
相关产品推荐
相关产品推荐

