浮动菜单扩展
在 Tiptap 中使用浮动菜单扩展,使菜单在空行上出现。
如果您正在使用类似 React 或 Vue 的框架,请使用这些框架特定的 FloatingMenu 组件,而不是扩展。该组件提供了更便利的 API,并为您处理 DOM 元素。有关该组件的更多信息,请参见下方的框架中的使用部分。
安装扩展
安装浮动菜单扩展和 Floating UI 库。
npm install @tiptap/extension-floating-menu @floating-ui/dom@^1.6.0设置
element
包含您菜单的 DOM 元素。
类型: HTMLElement
默认值: null
updateDelay
FloatingMenu 对 update 方法进行防抖,以避免在每次选择更新时都更新浮动菜单。该延迟以毫秒为单位控制。
FloatingMenuPlugin 默认延迟为 250 毫秒。将延迟设置为 0 可以禁用防抖。
类型: Number
默认值: 250
resizeDelay
FloatingMenu 对 resize 和 scroll 事件处理程序进行防抖,以避免在每次大小调整或滚动时都更新浮动菜单。该延迟以毫秒为单位控制。
类型: Number
默认值: 60
appendTo
菜单应附加到 DOM 中的元素。可以是一个 HTMLElement,也可以是返回 HTMLElement 的回调函数。
类型: HTMLElement | (() => HTMLElement) | undefined
默认值: undefined,菜单将附加到 document.body。
options
在底层,FloatingMenu 使用 Floating UI。您可以使用这些选项控制浮动菜单的中间件和定位。
类型: Object
默认值: { strategy: 'absolute', placement: 'right' }
| 选项 | 类型 | 描述 |
|---|---|---|
strategy | string | 定位策略。请参见 这里 |
placement | string | 菜单的位置。请参见 这里 |
offset | OffsetOptions 或 boolean | 偏移中间件选项。如果为 true 使用默认选项,如果为 false 禁用中间件 |
flip | FlipOptions 或 boolean | 翻转中间件选项。如果为 true 使用默认选项,如果为 false 禁用中间件 |
shift | ShiftOptions 或 boolean | 移动中间件选项。如果为 true 使用默认选项,如果为 false 禁用中间件 |
arrow | ArrowOptions 或 false | 箭头中间件选项。如果为 false 禁用中间件 |
size | SizeOptions 或 boolean | 大小中间件选项。如果为 true 使用默认选项,如果为 false 禁用中间件 |
autoPlacement | AutoPlacementOptions 或 boolean | 自动放置中间件选项。如果为 true 使用默认选项,如果为 false 禁用中间件 |
hide | HideOptions 或 boolean | 隐藏中间件选项。如果为 true 使用默认选项,如果为 false 禁用中间件的 |
inline | InlineOptions 或 boolean | 内联中间件选项。如果为 true 使用默认选项,如果为 false 禁用中间件 |
onShow | Function 或 undefined | 菜单显示时调用的回调。可用于在菜单显示时添加自定义逻辑或样式。 |
onHide | Function 或 undefined | 菜单隐藏时调用的回调。可用于在菜单隐藏时添加自定义逻辑或样式。 |
onUpdate | Function 或 undefined | 菜单更新时调用的回调。可用于在菜单更新时添加自定义逻辑或样式。 |
onDestroy | Function 或 undefined | 菜单销毁时调用的回调。可用于在菜单被移除时添加自定义逻辑或样式。 |
pluginKey
底层 ProseMirror 插件的键。如果您添加多个实例,请确保使用不同的键。
类型: string | PluginKey
默认值: 'floatingMenu'
shouldShow
一个回调,用于控制菜单是否应显示。
类型: (props) => boolean
源代码
packages/extension-floating-menu/
在 Vanilla JavaScript 中使用
import { Editor } from '@tiptap/core'
import FloatingMenu from '@tiptap/extension-floating-menu'
new Editor({
element: document.querySelector('#editor'),
extensions: [
StarterKit,
FloatingMenu.configure({
element: document.querySelector('#floating-menu'),
}),
],
content: '<p>Click on an empty line to see the floating menu.</p>',
})向您的 HTML 中添加一个菜单元素:
<div id="floating-menu" style="display: none; position: absolute;">
<button onclick="editor.chain().focus().toggleHeading({ level: 1 }).run()">H1</button>
<button onclick="editor.chain().focus().toggleBulletList().run()">List</button>
</div>
<div id="editor"></div>当光标位于空行上时,Tiptap 会自动显示并定位菜单元素。
使用框架
React
@tiptap/react 包提供了一个 FloatingMenu 组件,可以从 @tiptap/react/menus 导入。它提供了与扩展相同的功能,但使用了更适合 React 的 API。使用该组件时,无需将 FloatingMenu 扩展添加到编辑器中。
import { FloatingMenu } from '@tiptap/react/menus'
function MyFloatingMenu({ editor }) {
return (
<FloatingMenu editor={editor}>
<button onClick={() => editor.chain().focus().setHeading({ level: 1 }).run()}>
H1
</button>
<button onClick={() => editor.chain().focus().setBulletList().run()}>
List
</button>
</FloatingMenu>
)
}Vue
@tiptap/vue-3 包提供了一个 FloatingMenu 组件,可以从 @tiptap/vue-3/menus 导入。它提供了与扩展相同的功能,但使用了更适合 Vue 的 API。使用该组件时,无需将 FloatingMenu 扩展添加到编辑器中。
<template>
<FloatingMenu :editor="editor">
<button @click="editor.chain().focus().setHeading({ level: 1 }).run()">
H1
</button>
<button @click="editor.chain().focus().setBulletList().run()">
List
</button>
</FloatingMenu>
</template>
<script setup>
import { FloatingMenu } from '@tiptap/vue-3/menus'
// 确保将编辑器实例作为 prop 传递给 FloatingMenu 组件
const { editor } = defineProps({
editor: {
type: Object,
required: true,
},
})
</script>注意:相同的菜单也可在 Tiptap 的 Vue 2 版本中使用,可从 @tiptap/vue-2/menus 导入。
自定义逻辑
使用 shouldShow 选项自定义显示菜单的逻辑。对于组件,shouldShow 可以作为 prop 传递。
FloatingMenu.configure({
shouldShow: ({ editor, view, state, oldState }) => {
// 在任何段落中显示浮动菜单
return editor.isActive('paragraph')
},
})多个菜单
通过设置唯一的 pluginKey 使用多个菜单。
import { Editor } from '@tiptap/core'
import FloatingMenu from '@tiptap/extension-floating-menu'
new Editor({
extensions: [
FloatingMenu.configure({
pluginKey: 'floatingMenuOne',
element: document.querySelector('.menu-one'),
}),
FloatingMenu.configure({
pluginKey: 'floatingMenuTwo',
element: document.querySelector('.menu-two'),
}),
],
})或者,您可以传递一个 ProseMirror PluginKey。
import { Editor } from '@tiptap/core'
import FloatingMenu from '@tiptap/extension-floating-menu'
import { PluginKey } from '@tiptap/pm/state'
new Editor({
extensions: [
FloatingMenu.configure({
pluginKey: new PluginKey('floatingMenuOne'),
element: document.querySelector('.menu-one'),
}),
FloatingMenu.configure({
pluginKey: new PluginKey('floatingMenuTwo'),
element: document.querySelector('.menu-two'),
}),
],
})强制更新浮动菜单位置
如果浮动菜单在初始渲染后大小发生变化,其位置不会自动调整。要修复此问题,您可以在扩展上设置一个 pluginKey,并使用该键发送一个 'updatePosition' 事件来强制更新位置。
FloatingMenu.configure({
pluginKey: 'myFloatingMenu',
element: document.querySelector('.menu'),
})
editor.commands.setMeta('myFloatingMenu', 'updatePosition')要定位到特定的浮动菜单,请通过事务元数据发送一个 'updatePosition' 事件,并使用该菜单的 pluginKey:
FloatingMenu.configure({
pluginKey: 'myFloatingMenu',
element: document.querySelector('.menu'),
})例如,如果您有多个浮动菜单:
editor.commands.setMeta('floatingMenuOne', 'updatePosition')如果您使用 React 或 Vue 的 FloatingMenu 组件,并希望在外部触发 updatePosition,请先向组件传递一个明确的 pluginKey prop。若省略 pluginKey,组件会创建自己的 ProseMirror PluginKey,外部代码之后就无法可靠地引用它。
以编程方式显示或隐藏浮动菜单
您可以通过在扩展上设置一个 pluginKey,并使用该键派发带有 'show' 或 'hide' 元数据值的事务,以编程方式显示或隐藏浮动菜单。
// 显示浮动菜单
editor.commands.setMeta('myFloatingMenu', 'show')
// 隐藏浮动菜单
editor.commands.setMeta('myFloatingMenu', 'hide')注意: 派发 'show' 或 'hide' 会覆盖 shouldShow 中定义的行为。