当前位置: 首页 > news >正文

保姆级教程:用Lexical + React + Yjs,从零搭建一个支持多人实时编辑的在线文档(附完整代码)

从零构建实时协作文档:Lexical + React + Yjs 全栈实战指南

想象一下,当你和团队成员同时编辑同一份文档时,每个人的修改都能即时同步,光标位置清晰可见,就像在同一个房间里协作一样流畅。这种实时协作体验已经成为现代生产力工具的标配,而本文将带你从零开始,用Lexical、React和Yjs打造这样一个系统。

1. 环境准备与项目初始化

在开始之前,确保你的开发环境满足以下要求:

  • Node.js 16.x或更高版本
  • npm 8.x或yarn 1.22.x
  • 现代浏览器(Chrome/Firefox/Edge最新版)

创建一个全新的React项目作为我们的起点:

npx create-react-app collaborative-editor --template typescript cd collaborative-editor

接下来安装核心依赖:

npm install @lexical/react @lexical/rich-text yjs y-websocket npm install --save-dev @types/yjs @types/y-websocket

关键配置要点

  • 使用TypeScript模板以获得更好的类型安全
  • 选择y-websocket作为Yjs的WebSocket提供者
  • 安装对应的类型定义文件以支持TS开发

2. 构建基础编辑器组件

首先创建一个基础的Lexical编辑器组件EditorCore.tsx

import { LexicalComposer } from "@lexical/react/LexicalComposer"; import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin"; import { ContentEditable } from "@lexical/react/LexicalContentEditable"; import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin"; import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin"; import { EditorState } from "lexical"; const editorConfig = { namespace: "CollaborativeEditor", theme: { text: { bold: "font-bold", italic: "italic", underline: "underline", }, }, onError(error: Error) { console.error(error); }, }; export default function EditorCore() { return ( <LexicalComposer initialConfig={editorConfig}> <RichTextPlugin contentEditable={<ContentEditable className="min-h-[200px] p-2 border rounded" />} placeholder={<div className="text-gray-400 absolute top-2 left-2">开始输入...</div>} /> <HistoryPlugin /> <OnChangePlugin onChange={(editorState: EditorState) => { // 后续将在这里处理状态同步 }} /> </LexicalComposer> ); }

3. 实现实时协作核心架构

3.1 配置Yjs文档与WebSocket连接

创建collab.ts来管理协作状态:

import * as Y from 'yjs'; import { WebsocketProvider } from 'y-websocket'; // 创建共享文档实例 export const ydoc = new Y.Doc(); // 配置WebSocket连接 export const provider = new WebsocketProvider( 'ws://localhost:1234', // WebSocket服务器地址 'collab-demo', // 房间名 ydoc ); // 定义共享数据类型 export const ytext = ydoc.getText('content');

3.2 集成协作插件

修改编辑器组件以支持协作:

import { CollaborationPlugin } from "@lexical/yjs"; import { useYjs } from "./collab"; function CollaborativeEditor() { const { provider, ydoc } = useYjs(); return ( <LexicalComposer initialConfig={editorConfig}> <CollaborationPlugin id="main-editor" provider={provider} doc={ydoc} shouldBootstrap={true} /> {/* 其他插件... */} </LexicalComposer> ); }

3.3 实现用户状态显示

添加用户光标位置和状态的显示:

import { Cursor } from "@lexical/yjs"; function UserCursors() { const [cursors, setCursors] = useState<Cursor[]>([]); useEffect(() => { const awareness = provider.awareness; const handleAwarenessChange = () => { setCursors(Array.from(awareness.getStates().values())); }; awareness.on('change', handleAwarenessChange); return () => awareness.off('change', handleAwarenessChange); }, [provider]); return ( <div className="absolute top-2 right-2 space-y-1"> {cursors.map((cursor, i) => ( <div key={i} className="flex items-center"> <div className="w-3 h-3 rounded-full mr-2" style={{ backgroundColor: cursor.color }} /> <span>{cursor.name || '匿名用户'}</span> </div> ))} </div> ); }

4. 搭建后端同步服务

4.1 创建WebSocket服务器

使用Express和ws创建简单的WebSocket服务器:

const express = require('express'); const WebSocket = require('ws'); const { setupWSConnection } = require('y-websocket/bin/utils'); const app = express(); const port = 1234; const server = app.listen(port, () => { console.log(`WebSocket server running on ws://localhost:${port}`); }); const wss = new WebSocket.Server({ server }); wss.on('connection', (ws) => { setupWSConnection(ws); });

4.2 处理冲突解决策略

Yjs使用CRDT(Conflict-Free Replicated Data Type)算法自动解决冲突,但我们仍需要处理一些边界情况:

// 在客户端添加冲突处理逻辑 provider.on('sync', (isSynced: boolean) => { if (isSynced) { console.log('文档同步完成'); // 可以在这里添加同步完成后的处理逻辑 } }); // 处理连接状态变化 provider.on('status', (event: { status: string }) => { console.log('连接状态:', event.status); // 可以根据状态显示不同的UI提示 });

5. 部署与性能优化

5.1 生产环境部署配置

# 构建前端 npm run build # 使用PM2管理Node服务 pm2 start server.js --name "collab-server"

5.2 性能优化技巧

  • 文档分块:对于大型文档,考虑使用Yjs的Y.ArrayY.Map分块存储
  • 节流处理:对高频操作进行适当节流
  • 离线支持:使用IndexedDB持久化本地更改
import { IndexeddbPersistence } from 'y-indexeddb'; // 添加离线支持 const persistence = new IndexeddbPersistence('collab-demo', ydoc);

6. 高级功能扩展

6.1 实现版本历史记录

import { UndoManager } from 'yjs'; // 创建Undo管理器 const undoManager = new UndoManager(ytext, { captureTimeout: 500, // 操作合并时间窗口 }); // 在UI中添加撤销/重做按钮 function UndoRedoToolbar() { return ( <div className="flex space-x-2"> <button onClick={() => undoManager.undo()}>撤销</button> <button onClick={() => undoManager.redo()}>重做</button> </div> ); }

6.2 添加富文本格式支持

扩展基础编辑器以支持更多格式:

import { BoldPlugin, ItalicPlugin, UnderlinePlugin, LinkPlugin } from "@lexical/react/LexicalPlugins"; function RichTextPlugins() { return ( <> <BoldPlugin /> <ItalicPlugin /> <UnderlinePlugin /> <LinkPlugin /> </> ); }

在实际项目中,我们遇到的最常见挑战是处理大规模文档的同步延迟问题。通过将文档分块并按需加载,配合适当的UI加载指示器,可以显著提升用户体验。

http://www.cnnetsun.cn/news/1591794.html

相关文章:

  • Prose性能优化:如何让你的NLP应用运行速度提升4倍
  • Mustache部分模板详解:如何构建模块化视图组件
  • MusePublic圣光艺苑效果对比:4090 vs 3090在圣光艺苑中的性能差
  • Windows平台John the Ripper避坑指南:从安装到破解Shadow文件的完整流程
  • FastAPI JWT认证:完整选项配置指南
  • YOLOv11涨点改进| TGRS 2026 |全网独家创新、注意力改进篇| 引入PMM 金字塔掩码Mamba模块,逐步整合深层语义信息与浅层细节信息,含多种改进,助力小目标检测、图像分割高效涨点
  • 3步打造清爽Mac菜单栏:Dozer图标管理解决方案
  • Adafruit AGS02MA TVOC传感器Arduino驱动详解
  • AICoverGen深度解析:三步骤打造专业级AI翻唱作品
  • 终极Windows风扇智能控制指南:5步打造完美静音电脑
  • C 程序设计数组核心知识点梳理
  • RoboSense 16线激光雷达在Ubuntu1804和Windows下的点云图调试全攻略(附常见问题解决方案)
  • 【office2pdf】 项目规则(CLAUDE.md)
  • 如何快速配置NoteGen快捷键:从新手到效率高手的完整指南
  • Kubernetes 与大数据集成最佳实践
  • 深求·墨鉴HTTPS配置:Nginx反向代理,安全访问OCR工具
  • 医学图像拼接实战:如何用USID++解决低纹理场景的拼接难题
  • ssm+java2026年毕设数据分析教学网站【源码+论文】
  • 第195章 机械生态圈(秀秀)
  • 如何让Mac菜单栏不再杂乱?Dozer高效管理的3个隐藏技巧提升效率
  • VSCode插件管理进阶:用Shell脚本自动备份/恢复你的开发环境
  • ESP32-S3驱动ST7262+GT911的LVGL嵌入式GUI集成方案
  • Yi-Coder-1.5B数据库管理实战:MySQL安装配置与优化
  • 基础入门-计算机网络基础-常见协议详解:HTTP/HTTPS、TCP/UDP、ICMP、ARP
  • HC32F460的USB FIFO只有1.25KB?聊聊CherryUSB移植中那些必须手动调整的“坑”
  • 高云FPGA程序固化与下载全攻略:从逻辑到软核的实战指南
  • VSCode插件离线安装的隐藏技巧:如何批量安装.vsix文件提升效率
  • 胡桃讲编程:RVC 推理专项:不想用原版 RVC 推理?界面复杂?那么 —— 这款流明 AI 就是你的最佳选择!
  • OCR工具开发复盘:一个截图坐标问题的曲折解决之路
  • STM32环境监测系统在烟花爆竹仓库的应用