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

ReactJS实现Google Docs克隆:单工具栏控制多编辑器方案咨询

单工具栏控制多Jodit编辑器及多页面编辑器推荐

一、Jodit-react实现单工具栏控制多编辑器方案

核心思路是隐藏所有编辑器自带的工具栏,单独实现一个全局工具栏,通过监听编辑器容器的鼠标移入事件切换当前激活的编辑器,让工具栏操作指向激活的实例。

实现步骤与代码修改

  1. 统一编辑器配置:所有编辑器禁用自带工具栏,共享基础配置
  2. 管理编辑器实例:用对象ref存储所有编辑器实例,避免单个ref的冗余
  3. 跟踪激活编辑器:维护状态记录当前激活的编辑器实例
  4. 实现全局工具栏:添加自定义工具栏,点击按钮时调用激活编辑器的对应API

修改后的代码示例:

import React, { useMemo, useRef, useState } from "react";
import "jodit";
import "jodit/build/jodit.min.css";
import JoditEditor from "jodit-react";

const Editor = () => {
  // 用对象存储所有编辑器实例,key为page.id
  const editorsRef = useRef({});
  const [pages, setPages] = useState([
    { id: 1, content: "" },
    { id: 2, content: "" },
    { id: 3, content: "" },
  ]);
  // 记录当前激活的编辑器实例
  const [activeEditor, setActiveEditor] = useState(null);

  // 统一所有编辑器的配置,禁用自带工具栏
  const editorConfig = useMemo(
    () => ({
      height: 500,
      toolbar: false, // 隐藏自带工具栏
      readonly: false
    }),
    []
  );

  const handleContentChange = (content, pageId) => {
    setPages(prev => prev.map(page => 
      page.id === pageId ? { ...page, content } : page
    ));
  };

  // 编辑器挂载后保存实例到ref
  const handleEditorReady = (editor, pageId) => {
    editorsRef.current[pageId] = editor;
    // 默认激活第一个编辑器
    if (pageId === 1) setActiveEditor(editor);
  };

  // 鼠标移入编辑器容器时切换激活实例
  const handleEditorHover = (pageId) => {
    setActiveEditor(editorsRef.current[pageId]);
  };

  // 工具栏按钮点击事件,调用Jodit的命令
  const handleToolbarAction = (command) => {
    if (!activeEditor) return;
    // 调用Jodit的execCommand执行格式操作
    activeEditor.execCommand(command);
  };

  return (
    <>
      {/* 全局工具栏 */}
      <div style={{ padding: "10px", borderBottom: "1px solid #ccc", margin: "0 250px" }}>
        <button onClick={() => handleToolbarAction('bold')} style={{ marginRight: "8px" }}>粗体</button>
        <button onClick={() => handleToolbarAction('italic')} style={{ marginRight: "8px" }}>斜体</button>
        <button onClick={() => handleToolbarAction('underline')} style={{ marginRight: "8px" }}>下划线</button>
        <button onClick={() => handleToolbarAction('insertOrderedList')}>有序列表</button>
      </div>

      {/* 多编辑器容器 */}
      {pages.map((page) => (
        <div
          key={page.id}
          style={{ 
            border: activeEditor === editorsRef.current[page.id] ? "2px solid blue" : "2px solid red", 
            margin: "20px 250px" 
          }}
          onMouseEnter={() => handleEditorHover(page.id)}
        >
          <JoditEditor
            ref={editor => editor && handleEditorReady(editor, page.id)}
            value={page.content}
            config={editorConfig}
            tabIndex={page.id} // 给每个编辑器不同的tabIndex
            onChange={(newContent) => handleContentChange(newContent, page.id)}
          />
        </div>
      ))}
    </>
  );
};

export default Editor;

关键说明

  • 编辑器实例管理:通过handleEditorReady将每个编辑器实例存入editorsRef,方便后续调用
  • 激活切换:onMouseEnter事件触发时更新activeEditor,同时通过边框颜色区分激活状态
  • 工具栏操作:利用Jodit内置的execCommand方法执行格式命令,支持大部分常用编辑操作

二、支持多页面/多文档的编辑器推荐

如果需要更贴近Google Docs的多页面体验,以下编辑器更适合:

  • Slate.js:完全可定制的富文本编辑器框架,适合从零构建多页面文档系统。可自定义页面组件,共享工具栏逻辑,灵活控制每个页面的内容和状态。
  • CKEditor 5:支持构建多文档界面(MDI),可通过官方插件或自定义实现多个编辑器实例共享工具栏,同时提供成熟的富文本编辑能力。
  • TinyMCE:支持多编辑器实例管理,可通过API控制任意实例的编辑操作,自带丰富的工具栏组件,容易实现全局工具栏切换目标编辑器的逻辑。
  • Quill.js:轻量级富文本编辑器,可通过自定义模块和状态管理实现多页面共享工具栏,适合需要简洁界面的场景。

内容的提问来源于stack exchange,提问作者Asish Kumar Sharma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 12:15:12