探索 Tiptap V3 的最新功能

React

本指南描述了如何将 Tiptap 与您的 React 项目集成。我们使用 Vite,但其他设置的工作流程应该类似。

创建一个 React 项目(可选)

以一个名为 my-tiptap-project 的新 React 项目开始。 Vite 将设置我们所需的一切。

# 使用 npm 创建项目
npm create vite@latest my-tiptap-project -- --template react-ts

# 或者,使用 pnpm 创建项目
pnpm create vite@latest my-tiptap-project --template react-ts

# 或者,使用 yarn 创建项目
yarn create vite my-tiptap-project --template react-ts

# 进入目录
cd my-tiptap-project

安装依赖

接下来,安装 @tiptap/react 包,@tiptap/pm(ProseMirror 库)和 @tiptap/starter-kit,它包括启动时常用的扩展。

npm install @tiptap/react @tiptap/pm @tiptap/starter-kit

如果您按照步骤 1 和 2 操作,现在可以通过 npm run dev 启动项目,并在浏览器中打开 http://localhost:3000

集成 Tiptap

要实际开始使用 Tiptap,我们需要创建一个新组件。我们称其为 Tiptap,并在 src/Tiptap.tsx 中添加以下示例代码。

// src/Tiptap.tsx
import { EditorProvider } from '@tiptap/react'
import { FloatingMenu, BubbleMenu } from '@tiptap/react/menus'
import StarterKit from '@tiptap/starter-kit'

// 定义您的扩展数组
const extensions = [StarterKit]

const content = '<p>Hello World!</p>'

const Tiptap = () => {
  return (
    <EditorProvider extensions={extensions} content={content}>
      <FloatingMenu editor={null}>这是浮动菜单</FloatingMenu>
      <BubbleMenu editor={null}>这是气泡菜单</BubbleMenu>
    </EditorProvider>
  )
}

export default Tiptap

重要提示:如果您希望避免使用 Editor 上下文,可以随时使用 useEditor 钩子。

// src/Tiptap.tsx
import { useEditor, EditorContent } from '@tiptap/react'
import { FloatingMenu, BubbleMenu } from '@tiptap/react/menus'
import StarterKit from '@tiptap/starter-kit'

// 定义您的扩展数组
const extensions = [StarterKit]

const content = '<p>Hello World!</p>'

const Tiptap = () => {
  const editor = useEditor({
    extensions,
    content,
  })

  return (
    <>
      <EditorContent editor={editor} />
      <FloatingMenu editor={editor}>这是浮动菜单</FloatingMenu>
      <BubbleMenu editor={editor}>这是气泡菜单</BubbleMenu>
    </>
  )
}

export default Tiptap

将其添加到您的应用中

最后,用我们的新 Tiptap 组件替换 src/App.tsx 的内容。

import Tiptap from './Tiptap'

const App = () => {
  return (
    <div className="card">
      <Tiptap />
    </div>
  )
}

export default App

在子组件中消费编辑器上下文

如果您使用 EditorProvider 来设置您的 Tiptap 编辑器,则现在可以使用 useCurrentEditor 钩子从任何子组件访问您的编辑器实例。

import { useCurrentEditor } from '@tiptap/react'

const EditorJSONPreview = () => {
  const { editor } = useCurrentEditor()

  return <pre>{JSON.stringify(editor.getJSON(), null, 2)}</pre>
}

重要:如果您使用 useEditor 钩子来设置您的编辑器,则此方法无效。

您现在应该在浏览器中看到一个非常基础的 Tiptap 示例。

添加开始或结束插槽

由于 EditorContent 组件是由 EditorProvider 组件渲染的,因此我们现在无法直接定义在编辑器内容之前或之后渲染的位置。为此,我们可以在 EditorProvider 组件上使用 slotBeforeslotAfter 属性。

<EditorProvider
  extensions={extensions}
  content={content}
  slotBefore={<MyEditorToolbar />}
  slotAfter={<MyEditorFooter />}
/>

容器属性

EditorProvider 组件接受一个 editorContainerProps 属性来传递属性到编辑器提供器的容器元素。

<EditorProvider
  extensions={extensions}
  content={content}
  editorContainerProps={{ className: 'editor-container' }}
/>

响应编辑器状态变化

要响应编辑器状态变化,您可以使用 @tiptap/react 提供的 useEditorState 钩子。该钩子可用于从编辑器状态中获取信息,而不会导致编辑器组件或其子组件重新渲染。

import { useEditorState } from '@tiptap/react'

function MyEditorComponent() {
  // ... 您的编辑器设置代码

  const editorState = useEditorState({
    editor,

    // selector 函数用于选择您想要响应的状态
    selector: ({ editor }) => {
      if (!editor) return null;

      return {
        isEditable: editor.isEditable,
        currentSelection: editor.state.selection,
        currentContent: editor.getJSON(),
        // 您可以在这里添加更多的状态属性,如:
        // isBold: editor.isActive('bold'),
        // isItalic: editor.isActive('italic'),
      };
    },
  });
}

优化您的性能

我们建议您访问React 性能指南,以高效集成 Tiptap 编辑器。这将帮助您避免应用规模扩大时可能出现的问题。