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

Next.js中集成带History模块的React-Quill遇两大问题求助

Next.js 中 ReactQuill 历史模块图标缺失与自定义处理器问题解决

问题1:撤销/重做按钮图标缺失

动态导入 ReactQuill 时无法直接访问 ReactQuill.Quill,可通过以下两种方式解决:

方法1:动态导入时注册图标

修改动态导入逻辑,同时导入 Quill 核心库并注册默认图标:

const ReactQuill = dynamic(
  async () => {
    const { default: RQ } = await import("react-quill");
    // 直接导入Quill核心库
    const Quill = await import("quill");
    // 导入默认图标集
    const icons = Quill.import("ui/icons");
    // 若需自定义图标,可在此修改(示例:替换撤销图标)
    // icons.undo = '<svg viewBox="0 0 18 18"><path d="M10.5 1.5v4.5h4.5L9 12l-6-6h4.5V1.5h3z"/></svg>';
    // 注册图标
    Quill.register("ui/icons", icons, true);
    return ({ forwardedRef, ...props }) => <RQ ref={forwardedRef} {...props} />;
  },
  { ssr: false }
);

方法2:组件挂载后通过Ref设置图标

在组件的 useEffect 中,通过编辑器Ref获取Quill实例,再导入并设置图标:

useEffect(() => {
  if (quillRef.current) {
    const quill = quillRef.current.getEditor();
    const icons = quill.import("ui/icons");
    // 可选:自定义图标
    // icons.undo = '<svg>...</svg>';
    quill.register("ui/icons", icons, true);
    // 刷新工具栏
    quill.getModule("toolbar").render();
  }
}, []);

问题2:添加自定义处理器后编辑器消失

直接在 modules.toolbar.handlers 中定义处理器会因Quill实例未初始化导致异常,需通过Ref动态添加处理器:

  1. 保持 modules 中的 handlers 为空对象:
modules={{
  history: {
    delay: 2000,
    maxStack: 300,
    userOnly: true,
  },
  toolbar: {
    container: [/* 你的工具栏配置 */],
    handlers: {}, // 留空,后续动态添加
  },
}}
  1. 在 useEffect 中动态注册处理器:
useEffect(() => {
  if (quillRef.current) {
    const quill = quillRef.current.getEditor();
    const toolbarModule = quill.getModule("toolbar");
    
    // 自定义撤销处理器
    toolbarModule.addHandler("undo", () => {
      // 执行默认撤销逻辑
      quill.history.undo();
      // 添加你的自定义操作
      console.log("撤销操作已触发");
    });

    // 自定义重做处理器
    toolbarModule.addHandler("redo", () => {
      quill.history.redo();
      console.log("重做操作已触发");
    });
  }
}, [quillRef.current]);

完整修改后的代码

import dynamic from "next/dynamic";
import showdown from "showdown";
import "react-quill/dist/quill.snow.css";
import { useState, useEffect, useRef } from "react";
import React from "react";
import styles from "./Editor.module.css";

const converter = new showdown.Converter();

// 动态导入ReactQuill并注册图标
const ReactQuill = dynamic(
  async () => {
    const { default: RQ } = await import("react-quill");
    const Quill = await import("quill");
    const icons = Quill.import("ui/icons");
    Quill.register("ui/icons", icons, true);
    return ({ forwardedRef, ...props }) => <RQ ref={forwardedRef} {...props} />;
  },
  { ssr: false }
);

export default function Editor({ title, body = "" }) {
  const quillRef = useRef(null);
  const text = title ? "# " + title + "\n\n" + body : body;
  const initialHtml = converter.makeHtml(text);
  const [html, setHtml] = useState(initialHtml);

  useEffect(() => {
    if (quillRef.current) {
      const quill = quillRef.current.getEditor();
      const toolbarModule = quill.getModule("toolbar");

      // 自定义撤销处理器
      toolbarModule.addHandler("undo", () => {
        quill.history.undo();
        console.log("撤销操作触发");
      });

      // 自定义重做处理器
      toolbarModule.addHandler("redo", () => {
        quill.history.redo();
        console.log("重做操作触发");
      });
    }
  }, [quillRef.current]);

  return (
    <ReactQuill
      forwardedRef={quillRef}
      theme="snow"
      value={html}
      onChange={setHtml}
      modules={{
        history: {
          delay: 2000,
          maxStack: 300,
          userOnly: true,
        },
        toolbar: {
          container: [
            [{ header: [1, 2, 3, 4, 5, 6, false] }],
            ["bold", "italic", "underline"],
            [{ list: "ordered" }, { list: "bullet" }],
            ["link"],
            ["undo", "redo", "image"],
          ],
          handlers: {},
        },
      }}
    />
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 10:17:06