You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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格式。

次要问题解答

  1. 高亮标签不在onChange输出的原因:
    Quill的syntax模块在代码块中是将高亮作为代码块的内部格式处理,不会输出额外HTML标签——代码块内容以纯文本+语法类形式存储,onChange输出的是<pre><code>...</code></pre>,高亮通过CSS类实现,不会嵌入标签。

  2. 脱离代码块后高亮标签是否会进入输出:
    是的。撤销代码块后,syntax模块的高亮会被转换为带highlight.js类的普通HTML span标签,这些标签会出现在onChange的HTML输出中。而我们自定义的Blot,按上述配置后,onChange输出会包含<span class="merge-field-highlight">...</span>,可根据需求在输出时选择保留、替换或移除这些标签。

内容的提问来源于stack exchange,提问作者Grank

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 15:28:32