项目

协作安装指南

本指南将指导您在 Tiptap 编辑器中启用协作编辑。如果您已经在使用 Tiptap 编辑器,可以直接跳到“添加协作”部分。

安装 Tiptap 编辑器

如果没有安装 Tiptap 编辑器,请使用以下命令在您的 CLI 中为 React 或 Vue 项目安装基本编辑器和示例所需的扩展:

npm install @tiptap/extension-document @tiptap/extension-paragraph @tiptap/extension-text @tiptap/react

安装完成后,您可以使用这个基础设置启动 Tiptap 编辑器。只需在项目中添加以下代码片段: https://embed.tiptap.dev/preview/Examples/Minimal

添加协作

要在您的 Tiptap 编辑器中引入团队协作功能,需要将 Yjs 库和协作扩展集成到前端。此设置使用共享文档模型 Y.Doc,而不仅仅是处理纯文本。

接下来,我们将连接 Y.Doc 到 TiptapCollabProvider,以同步用户交互。

集成 Yjs 和协作扩展

将协作扩展和 Yjs 库添加到您的前端:

npm install @tiptap/extension-collaboration yjs

然后,在 index.jsx 文件中添加这些新的导入:

import './styles.scss'

import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import { EditorContent, useEditor } from '@tiptap/react'
import React from 'react'

import Collaboration from '@tiptap/extension-collaboration'
import * as Y from 'yjs'

export default () => {
  const doc = new Y.Doc() // 初始化 Y.Doc 用于共享编辑

  const editor = useEditor({
    extensions: [
      Document,
      Paragraph,
      Text,
      Collaboration.configure({
        document: doc // 将 Y.Doc 配置为协作
      })
    ],
    content: `  
      <p>
        这是 Tiptap 的极简版本。它支持文档,包含段落和文本。仅此而已。对于真正的极简主义者来说可能有点多了。
      </p>
      <p>
        段落扩展实际上并不必要,但至少需要一个节点。当然,这个节点可以是不同的东西。
      </p>
    `,
  })

  return (
    <EditorContent editor={editor} />
  )
}

现在,您的编辑器已经准备好进行协作编辑!

连接至协作服务器

为了实现协作功能,请安装 @hocuspocus/provider 包:

npm install @hocuspocus/provider

接下来,在 index.jsx 文件中根据您的服务器详细信息配置 Hocuspocus 提供者:

  • name:用作同步标识符的文档名称。
  • appID:在您的 云端账户中启动应用后,将在云界面中找到。对于本地部署,请将 appID 替换为 baseUrl
  • token:测试时使用云端接口的 JWT,但生产环境请生成自己的 JWT。

添加以下代码以完成设置:

import './styles.scss'

import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import { EditorContent, useEditor } from '@tiptap/react'
import React from 'react'

import Collaboration from '@tiptap/extension-collaboration'
import * as Y from 'yjs'

// 导入提供者和 useEffect
import {useEffect} from 'react'
import { TiptapCollabProvider } from '@hocuspocus/provider'

export default () => {
  const doc = new Y.Doc()

  const editor = useEditor({
    extensions: [
      Document,
      Paragraph,
      Text,
      Collaboration.configure({
        document: doc,
      }),
    ],
    content: `  
      <p>
        这是 Tiptap 的极简版本。它支持文档,包含段落和文本。仅此而已。对于真正的极简主义者来说可能有点多了。
      </p>
      <p>
        段落扩展实际上并不必要,但至少需要一个节点。当然,这个节点可以是不同的东西。
      </p>
    `,
  })

  // 连接到您的协作服务器
  useEffect(() => {
    const provider = new TiptapCollabProvider({
      name: "document.name", // 文档名称用于同步。这是您的文档名。
      appId: '7j9y6m10', // 云端仪表板 AppID 或 `baseURL`(本地部署)
      token: 'notoken', // 测试时使用的 JWT 或生产环境自定义的 JWT
      document: doc,
      
      // onSynced 回调确保只在初次加载时设置初始内容,防止每次编辑器同步时重复加载内容。
      onSynced() {

        if( !doc.getMap('config').get('initialContentLoaded') && editor ){
          doc.getMap('config').set('initialContentLoaded', true);

          editor.commands.setContent(`  
          <p>
          这是 Tiptap 的极简版本。它支持文档,包含段落和文本。仅此而已。对于真正的极简主义者来说可能有点多了。
        </p>
        <p>
          段落扩展实际上并不必要,但至少需要一个节点。当然,这个节点可以是不同的东西。
        </p>
          `)
        }

      }
    })
  })

  return (
    <EditorContent editor={editor} />
  )
}

遵循这些步骤后,您应该能够在两个不同的浏览器中通过单独的 WebSocket 连接同时连接到同一文档。

为了清楚地测试协作功能,建议使用两个不同的浏览器,以确保唯一的 WebSocket 连接。

正确初始化内容

在 Tiptap 编辑器中启用协作后,可能会发现每次编辑器加载时初始内容都会重复添加。为了防止这种情况,使用 .setContent() 方法仅设置一次初始内容。

import './styles.scss'

import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import { EditorContent, useEditor } from '@tiptap/react'
import React from 'react'

import * as Y from 'yjs'
import Collaboration from '@tiptap/extension-collaboration'
import {useEffect} from 'react'

import { TiptapCollabProvider } from '@hocuspocus/provider'

export default () => {
  const doc = new Y.Doc()

  const editor = useEditor({
    extensions: [
      Document,
      Paragraph,
      Text,
      Collaboration.configure({
        document: doc
      })
    ],
    // 移除编辑器初始化时自动添加内容的代码。
  })
  
  useEffect(() => {
    const provider = new TiptapCollabProvider({
      name: "document.name", // 文档名称用于同步。这是您的文档名。
      appId: '7j9y6m10', // 云端仪表板 AppID 或 `baseURL`(本地部署)
      token: 'notoken', // 测试时使用的 JWT 或生产环境自定义的 JWT
      document: doc,
      
      // onSynced 回调确保只在初次加载时设置初始内容。
      onSynced() {

        if( !doc.getMap('config').get('initialContentLoaded') && editor ){
          doc.getMap('config').set('initialContentLoaded', true);

          // 使用 editor.setContent() 设置初始内容,避免每次编辑器同步时重复加载。
          editor.commands.setContent(`  
          <p>
          这是 Tiptap 的极简版本。它支持文档,包含段落和文本。仅此而已。对于真正的极简主义者来说可能有点多了。
        </p>
        <p>
          段落扩展实际上并不必要,但至少需要一个节点。当然,这个节点可以是不同的东西。
        </p>
          `)
        }

      }
    })
  })

  return (
    <EditorContent editor={editor} />
  )
}

这将确保只设置一次初始内容。要测试不同的初始内容,请更改 name 参数(例如,从 document.name 更改为 document.name2)创建新的文档。

禁用默认撤销/重做功能

如果将协作集成到本示例之外的编辑器中,您可能需要禁用编辑器的默认历史功能。这是必要的,以避免与协作历史管理冲突:您不希望撤销或重做其他人的更改。

此操作仅在您的项目中包含 Tiptap StarterKitHistory 扩展时才需要。

const editor = useEditor({
  extensions: [
    StarterKit.configure({
      history: false, // 禁用默认历史,使用协作的管理历史功能
    }),
...

遵循本指南,您将设置一个基本但功能齐全的协作 Tiptap 编辑器,通过

在本文档中