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

QuillJS添加自定义Blot支持Freemarker标签的问题求助

问题

已集成Quill编辑器作为在线模板编辑器,后端采用Freemarker处理模板,需要Quill支持Freemarker标签(如<#list>)。目前设置了自定义按钮切换至纯HTML视图编辑标记,添加模板内容切回Quill后,标签会被转义且包裹在<p>标签中。尝试过如下自定义Blot但无效,#符号始终被转义:

class FMListBlot extends InlineBlot {}
FMListBlot.blotName = "fmlist";
FMListBlot.tagName = "#list";
FMListBlot.scope = Scope.INLINE;
Quill.register(FMListBlot);

需求:允许Quill保留自定义Freemarker标签,无需可视化展示,只要不清理转义即可。

解决方案

核心问题说明

Quill的默认HTML解析器会过滤非标准HTML标签(标签名含#属于非法HTML),且自定义Blot的标签名必须符合HTML规范,因此直接用#list作为tagName无法被识别。以下是可行的实现方案:


方案1:自定义Blot+Clipboard处理(推荐)

通过合法HTML标签承载Freemarker内容,自定义Clipboard模块处理标签转换,避免Quill转义清理。

1. 定义自定义Inline Blot

用标准<span>标签承载Freemarker标签,添加类名标识:

import Quill from 'quill';
const Inline = Quill.import('blots/inline');

class FMListBlot extends Inline {
  static create(value) {
    const node = super.create();
    node.innerHTML = value;
    node.classList.add('fm-freemarker-tag');
    return node;
  }

  static value(node) {
    return node.innerHTML;
  }
}

FMListBlot.blotName = 'freemarkerTag';
FMListBlot.tagName = 'SPAN';
Quill.register(FMListBlot);

2. 自定义Clipboard模块处理HTML转换

在粘贴或切换回富文本视图时,自动将<#list>标签转换为自定义Blot对应的<span>:

const Clipboard = Quill.import('modules/clipboard');

class FMClipboard extends Clipboard {
  // 处理粘贴事件
  onPaste(e) {
    const html = e.clipboardData?.getData('text/html');
    if (!html) return super.onPaste(e);

    // 将所有Freemarker标签包裹到自定义span中
    const processedHtml = html.replace(
      /<#([a-z]+)([^>]*)>([\s\S]*?)<\/#\1>/g,
      '<span class="fm-freemarker-tag"><#$1$2>$3</#$1></span>'
    );

    // 替换编辑器内容
    this.quill.scroll.deleteAt(0, this.quill.getLength());
    this.quill.clipboard.dangerouslyPasteHTML(0, processedHtml);
    e.preventDefault();
  }

  // 手动处理HTML视图返回的内容(配合你的切换按钮使用)
  processRawHtml(rawHtml) {
    return rawHtml.replace(
      /<#([a-z]+)([^>]*)>([\s\S]*?)<\/#\1>/g,
      '<span class="fm-freemarker-tag"><#$1$2>$3</#$1></span>'
    );
  }
}

// 替换默认Clipboard模块
Quill.register('modules/clipboard', FMClipboard, true);

3. 输出时还原Freemarker标签

将编辑器内容导出给后端前,把自定义<span>转换回原始Freemarker标签:

const editorHtml = quill.root.innerHTML;
const finalTemplate = editorHtml.replace(
  /<span class="fm-freemarker-tag">(<#[a-z]+[^>]*>[\s\S]*?<\/#[\w]+>)<\/span>/g,
  '$1'
);
// 将finalTemplate传给后端

方案2:关闭Quill内容 sanitize(不推荐公共环境)

如果场景不存在XSS风险,可直接关闭Quill的内容清理,但仍需处理非法标签的解析问题:

const quill = new Quill('#editor', {
  theme: 'snow',
  sanitize: false, // 关闭默认内容清理
  modules: {
    // 其他模块配置
  }
});

此方法仅能避免Quill主动转义,但浏览器仍会将<#list>视为无效标签,最终可能被包裹到<p>中,因此仍需结合方案1的Clipboard处理才能稳定保留标签。


内容的提问来源于stack exchange,提问作者David Fariña

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:55:22