---
title: "BubbleMenu 扩展"
description: "添加一个弹出在 Tiptap 编辑器文本内容上方的菜单工具栏。请在我们的文档中了解更多信息！"
canonical_url: "https://tiptap.zhcndoc.com/editor/extensions/functionality/bubble-menu"
---

# BubbleMenu 扩展

添加一个弹出在 Tiptap 编辑器文本内容上方的菜单工具栏。请在我们的文档中了解更多信息！

此扩展会在文本选择附近显示上下文菜单。用户可以对其文本选择应用 [标记](https://tiptap.zhcndoc.com/editor/extensions/marks.md)。

和往常一样，标记和样式完全由您决定。

> **Interactive demo:** [BubbleMenu](https://embed.tiptap.dev/preview/Extensions/BubbleMenu)

> **Warning:**
>
> 如果您使用的是 React 或 Vue 等框架，请使用特定于框架的 `BubbleMenu` 组件，而不是扩展。该组件提供了更方便的 API，并为您处理 DOM 元素。您可以在下方的[与框架一起使用](#usage-with-frameworks)章节中找到有关该组件的更多信息。

## 安装

```bash
npm install @tiptap/extension-bubble-menu
```

## 设置

### element

包含您的菜单的 DOM 元素。

类型: `HTMLElement`

默认: `null`

在 React 版本的 `BubbleMenu` 中，可通过 `BubbleMenu` 组件的 `ref` 属性访问 DOM 元素，方法是将 [ref 传递](https://react.dev/learn/manipulating-the-dom-with-refs) 给它。

### updateDelay

`BubbleMenu` 会对 `update` 方法进行去抖动，以允许气泡菜单不会在每次选择更新时进行更新。此延迟可以以毫秒为单位进行控制。

`BubbleMenuPlugin` 默认有 250 毫秒的延迟。将延迟设置为 `0` 可禁用该功能，从而禁用去抖动。

类型: `Number`

默认: `undefined`

### resizeDelay

`BubbleMenu` 会对气泡菜单大小的计算进行去抖动，以允许气泡菜单不会在每次调整大小事件时更新。此延迟可以以毫秒为单位进行控制。

类型: `Number`

默认: `100`

### options

在底层，`BubbleMenu` 使用 [Floating UI](https://floating-ui.com)。您可以使用这些选项控制浮动菜单的中间件和定位。

类型: `Object`

默认: `{ strategy: 'absolute', placement: 'right' }`

| 选项              | 类型                                    | 描述                                                                                                    |
| --------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `strategy`      | `string`                              | 定位策略。请参见 [这里](https://floating-ui.com/docs/computePosition#strategy)                                  |
| `placement`     | `string`                              | 菜单的位置。请参见 [这里](https://floating-ui.com/docs/computePosition#placement)                                |
| `offset`        | `number`, `OffsetOptions` 或 `boolean` | [偏移中间件选项](https://floating-ui.com/docs/offset#options)。如果为 `true`，则使用默认选项；如果为 `false`，则禁用中间件          |
| `flip`          | `FlipOptions` 或 `boolean`             | [翻转中间件选项](https://floating-ui.com/docs/flip#options)。如果为 `true`，则使用默认选项；如果为 `false`，则禁用中间件            |
| `shift`         | `ShiftOptions` 或 `boolean`            | [移动中间件选项](https://floating-ui.com/docs/shift#options)。如果为 `true`，则使用默认选项；如果为 `false`，则禁用中间件           |
| `arrow`         | `ArrowOptions` 或 `false`              | [箭头中间件选项](https://floating-ui.com/docs/arrow#options)。如果为 `false`，则禁用中间件                              |
| `size`          | `SizeOptions` 或 `boolean`             | [大小中间件选项](https://floating-ui.com/docs/size#options)。如果为 `true`，则使用默认选项；如果为 `false`，则禁用中间件            |
| `autoPlacement` | `AutoPlacementOptions` 或 `boolean`    | [自动定位中间件选项](https://floating-ui.com/docs/autoPlacement#options)。如果为 `true`，则使用默认选项；如果为 `false`，则禁用中间件 |
| `hide`          | `HideOptions` 或 `boolean`             | [隐藏中间件选项](https://floating-ui.com/docs/hide#options)。如果为 `true`，则使用默认选项；如果为 `false`，则禁用中间件            |
| `inline`        | `InlineOptions` 或 `boolean`           | [内联中间件选项](https://floating-ui.com/docs/inline#options)。如果为 `true`，则使用默认选项；如果为 `false`，则禁用中间件          |
| `onShow`        | `Function` 或 `undefined`              | 菜单显示时调用的回调函数。可用于在菜单显示时添加自定义逻辑或样式。                                                                     |
| `onHide`        | `Function` 或 `undefined`              | 菜单隐藏时调用的回调函数。可用于在菜单隐藏时添加自定义逻辑或样式。                                                                     |
| `onUpdate`      | `Function` 或 `undefined`              | 菜单更新时调用的回调函数。可用于在菜单更新时添加自定义逻辑或样式。                                                                     |
| `onDestroy`     | `Function` 或 `undefined`              | 菜单销毁时调用的回调函数。可用于在菜单移除时添加自定义逻辑或样式。                                                                     |

### pluginKey

底层 ProseMirror 插件的键。如果添加多个实例，请确保使用不同的键。

类型: `string | PluginKey`

默认: `'bubbleMenu'`

### shouldShow

一个回调，用于控制菜单是否应该显示。

类型: `(props) => boolean`

### appendTo

气泡菜单应该被附加到 DOM 中的元素。可以是 `HTMLElement`，也可以是返回 `HTMLElement` 的回调函数。

类型: `HTMLElement | (() => HTMLElement) | undefined`

默认: `undefined`，菜单将附加到编辑器的父元素（`editor.view.dom.parentElement`）。

### getReferencedVirtualElement

一个回调，用于提供用于定位菜单的锚点坐标。应返回 Floating UI 预期的 [虚拟元素](https://floating-ui.com/docs/virtual-elements)。

类型: `() => VirtualElement | null`

默认: `null`，锚点由编辑器选区隐式确定。

## 源代码

[packages/extension-bubble-menu/](https://github.com/ueberdosis/tiptap/blob/main/packages/extension-bubble-menu/)

## 使用扩展

### JavaScript

```js
import { Editor } from '@tiptap/core'
import BubbleMenu from '@tiptap/extension-bubble-menu'

new Editor({
  element: document.querySelector('#editor'),
  extensions: [
    StarterKit,
    BubbleMenu.configure({
      element: document.querySelector('#bubble-menu'),
    }),
  ],
  content: '<p>Select some text to see the bubble menu.</p>',
})
```

向您的 HTML 中添加一个菜单元素：

```html
<div id="bubble-menu" style="display: none; position: absolute;">
  <button onclick="editor.chain().focus().toggleBold().run()">加粗</button>
  <button onclick="editor.chain().focus().toggleItalic().run()">斜体</button>
</div>
<div id="editor"></div>
```

当选中文本时，Tiptap 会自动显示并定位菜单元素。

## 与框架一起使用

#### React

`@tiptap/react` 包含一个可从 `@tiptap/react/menus` 导入的 `BubbleMenu` 组件。它提供与扩展相同的功能，但采用了更适合 React 的 API。使用此组件时，无需将 `BubbleMenu` 扩展添加到编辑器中。

```jsx
import { BubbleMenu } from '@tiptap/react/menus'

function MyBubbleMenu({ editor }) {
  return (
    <BubbleMenu editor={editor}>
      <button onClick={() => editor.chain().focus().toggleBold().run()}>
        加粗
      </button>
      <button onClick={() => editor.chain().focus().toggleItalic().run()}>
        斜体
      </button>
    </BubbleMenu>
  )
}
```

#### Vue

`@tiptap/vue-3` 包含一个可从 `@tiptap/vue-3/menus` 导入的 `BubbleMenu` 组件。它提供与扩展相同的功能，但采用了更适合 Vue 的 API。使用此组件时，无需将 `BubbleMenu` 扩展添加到编辑器中。

```vue
<template>
  <BubbleMenu :editor="editor">
    <button @click="editor.chain().focus().toggleBold().run()">
      加粗
    </button>
    <button @click="editor.chain().focus().toggleItalic().run()">
      斜体
    </button>
  </BubbleMenu>
</template>

<script setup>
  import { BubbleMenu } from '@tiptap/vue-3/menus'
  
  // 确保将编辑器实例作为属性传递给 BubbleMenu 组件
  const { editor } = defineProps({
    editor: {
      type: Object,
      required: true,
    },
  })
</script>
```

**注意**：相同的菜单也可用于 Vue 2 版本的 Tiptap，您可以从 `@tiptap/vue-2/menus` 导入。

### 自定义逻辑

使用 `shouldShow` 选项自定义显示菜单的逻辑。对于组件，`shouldShow` 可以作为道具传递。

```js
BubbleMenu.configure({
  shouldShow: ({ editor, view, state, oldState, from, to }) => {
    // 仅对图像和链接显示气泡菜单
    return editor.isActive('image') || editor.isActive('link')
  },
})
```

### 多个菜单

通过设置唯一的 `pluginKey` 使用多个菜单。

```js
import { Editor } from '@tiptap/core'
import BubbleMenu from '@tiptap/extension-bubble-menu'

new Editor({
  extensions: [
    BubbleMenu.configure({
      pluginKey: 'bubbleMenuOne',
      element: document.querySelector('.menu-one'),
    }),
    BubbleMenu.configure({
      pluginKey: 'bubbleMenuTwo',
      element: document.querySelector('.menu-two'),
    }),
  ],
})
```

或者，您可以传递一个 ProseMirror `PluginKey`。

```js
import { Editor } from '@tiptap/core'
import BubbleMenu from '@tiptap/extension-bubble-menu'
import { PluginKey } from '@tiptap/pm/state'

new Editor({
  extensions: [
    BubbleMenu.configure({
      pluginKey: new PluginKey('bubbleMenuOne'),
      element: document.querySelector('.menu-one'),
    }),
    BubbleMenu.configure({
      pluginKey: new PluginKey('bubbleMenuTwo'),
      element: document.querySelector('.menu-two'),
    }),
  ],
})
```

### 强制更新气泡菜单位置

如果气泡菜单在初始渲染后改变了大小，其位置不会自动调整。要解决此问题，您可以通过在扩展上设置 `pluginKey`，并使用该键发出 `'updatePosition'` 事件来强制更新位置。

```ts
BubbleMenu.configure({
  pluginKey: 'myBubbleMenu',
  element: document.querySelector('.menu'),
})

editor.commands.setMeta('myBubbleMenu', 'updatePosition')
```

要针对特定的气泡菜单，请改为传递该菜单的 `pluginKey`。

```ts
editor.commands.setMeta('bubbleMenuOne', 'updatePosition')
```

如果您使用 React 或 Vue 的 `BubbleMenu` 组件，并希望在外部触发 `updatePosition`，请先为组件传入一个明确的 `pluginKey` 属性。如果省略 `pluginKey`，组件会创建自己的 ProseMirror `PluginKey`，外部代码之后无法可靠地引用它。

### 以编程方式显示或隐藏气泡菜单

您可以通过在扩展上设置 `pluginKey`，并使用该键分发带有 `'show'` 或 `'hide'` 元值的事务，来以编程方式显示或隐藏气泡菜单。

```ts
BubbleMenu.configure({
  pluginKey: 'myBubbleMenu',
  element: document.querySelector('.menu'),
})

// 显示气泡菜单
editor.commands.setMeta('myBubbleMenu', 'show')

// 隐藏气泡菜单
editor.commands.setMeta('myBubbleMenu', 'hide')
```

**注意：** 分发 `'show'` 或 `'hide'` 将覆盖 `shouldShow` 中定义的行为。
