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

ReactQuill编辑器图片上传报错:quillRef定义及图片处理器实现

解决ReactQuill图片上传Handler的Range初始化问题

核心问题分析

  • quillRef.current可能在组件未完全挂载时被调用,导致getEditor()返回undefined
  • 未判断range是否存在,当编辑器无选中内容时quill.getSelection(true)会返回null,直接访问range.index会触发报错
  • 代码中存在语法错误(-setTheme("bubble")多了减号)
  • 未导入提示组件却调用了toast.error

修复步骤

1. 安全获取Quill实例与选区

在imageHandler中增加实例存在性判断,同时处理无选区的边界情况:

const imageHandler = () => {
  const input = document.createElement("input");
  input.setAttribute("type", "file");
  input.setAttribute("accept", "image/*");
  input.click();

  input.onChange = async (e) => {
    const file = e.target.files[0];
    if (!file) return;

    // 确保Quill组件实例已挂载
    if (!quillRef.current) return;
    const quill = quillRef.current.getEditor();
    if (!quill) return;

    // 处理无选区的情况,默认插入到编辑器末尾
    let range = quill.getSelection(true);
    if (!range) {
      const editorLength = quill.getLength();
      range = { index: editorLength - 1, length: 0 };
    }

    // 插入临时加载占位图
    quill.insertEmbed(
      range.index,
      "image",
      `${window.location.origin}/images/loaders/placeholder.gif`
    );
    quill.setSelection(range.index + 1);

    try {
      const formData = new FormData();
      formData.append("image", file);
      const { data } = await axios.post("/uploadImage", formData);
      
      if (data.error) {
        message.error(data.error);
        quill.deleteText(range.index, 1);
        return;
      }

      setImage2({ url: data.url, public_id: data.public_id });
      // 替换占位图为真实图片
      quill.deleteText(range.index, 1);
      quill.insertEmbed(range.index, "image", data.url);
    } catch (err) {
      console.error(err);
      quill.deleteText(range.index, 1);
      message.error("图片上传失败,请重试");
    }
  };
};

2. 修正语法错误

修复handleThemeChange中的无效代码:

const handleThemeChange = (newTheme) => {
  if (newTheme === "bubble") {
    setTheme("bubble");
  } else if (newTheme === "snow") {
    setTheme("snow");
  }
};

3. 移除不必要的依赖

ReactQuill内部已包含Quill实例,无需单独动态导入,删除以下代码:

const Quill = dynamic(() => import("quill"), { ssr: false });

4. 导入提示组件

在文件顶部导入antd的提示组件:

import { message } from "antd";

5. 确认Ref绑定有效性

可以通过useEffect验证Quill实例是否正确初始化:

useEffect(() => {
  if (quillRef.current) {
    const quill = quillRef.current.getEditor();
    console.log("Quill实例已初始化", quill);
  }
}, []);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 02:32:47