Tiptap Bubble Menu 气泡菜单

Tiptap BubbleMenu 浮动菜单扩展,当选中对象菜单将悬浮在鼠标附近,你可以对选中的标记mark进行操作。

Install 安装

npm install @tiptap/extension-bubble-menu

Settings 配置

element 包含菜单的元素,默认为null。

BubbleMenu.configure({
  element: null,
})

updateDelay BubbleMenu取消了更新方法,允许在每次选择更新时不更新气泡菜单。这可以在毫秒内控制。BubbleMenuPlugin的默认延迟为250ms。这可以通过将延迟设置为0来停用。

BubbleMenu.configure({
  updateDelay: 0,
})

tippyOptions BubbleMenu使用tippy.js,您可以直接将配置传递给它。

BubbleMenu.configure({
  tippyOptions: { },
})

pluginKey 当有多个实例时你需要用到这个参数,默认为bubbleMenu。

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'),
    }),
  ],
})

shouldShow 一个控制菜单是否显示的回调函数。

BubbleMenu.configure({
  shouldShow: ({ editor, view, state, oldState, from, to }) => {
    //如果是图片或链接才显示菜单
    return editor.isActive('image') || editor.isActive('link')
  },
})

Usage 用例

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

new Editor({
  extensions: [
    BubbleMenu.configure({
      element: document.querySelector('.menu'),
    }),
  ],
})

源代码

bubble-menu 源代码

在线例子

vue 在线例子

BubbleMenu 例子

  • Vue 例子

  • React 例子

  • React CSS

<template>
  <div>
    <div>
      <input type="checkbox" :checked="isEditable" @change="() => isEditable = !isEditable">
      Editable
    </div>
    <bubble-menu
      :editor="editor"
      :tippy-options="{ duration: 100 }"
      v-if="editor"
    >
      <button @click="editor.chain().focus().toggleBold().run()" :class="{ 'is-active': editor.isActive('bold') }">
        bold
      </button>
      <button @click="editor.chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
        italic
      </button>
      <button @click="editor.chain().focus().toggleStrike().run()" :class="{ 'is-active': editor.isActive('strike') }">
        strike
      </button>
    </bubble-menu>
    <editor-content :editor="editor" />
  </div>
</template>
<script>
import StarterKit from '@tiptap/starter-kit'
import { BubbleMenu, Editor, EditorContent } from '@tiptap/vue-3'

export default {
  components: {
    EditorContent,
    BubbleMenu,
  },
  data() {
    return {
      editor: null,
      isEditable: true,
    }
  },
  watch: {
    isEditable(value) {
      this.editor.setEditable(value)
    },
  },
  mounted() {
    this.editor = new Editor({
      extensions: [
        StarterKit,
      ],
      content: `
        <p>
          IT小书童 - 为程序员提供优质教程和文档,你选择几个文字试试看 www.itxst.com
        </p>
      `,
    })
  },
  beforeUnmount() {
    this.editor.destroy()
  },
}
</script>
<style>
/* Basic editor styles */
.ProseMirror {
  > * + * {
    margin-top: 0.75em;
  }
}

input[type="checkbox"] {
  margin-right: 4px;
}
</style>
import './styles.scss'
import {
  BubbleMenu, EditorContent, useEditor,
} from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import React, { useEffect } from 'react'

export default () => {
  const editor = useEditor({
    extensions: [
      StarterKit,
    ],
    content: `
      <p>
        Hey, try to select some text here. There will popup a menu for selecting some inline styles. Remember: you have full control about content and styling of this menu.
      </p>
    `,
  })

  const [isEditable, setIsEditable] = React.useState(true)

  useEffect(() => {
    if (editor) {
      editor.setEditable(isEditable)
    }
  }, [isEditable, editor])
  return (
    <>
      <div>
        <input type="checkbox" checked={isEditable} onChange={() => setIsEditable(!isEditable)} />
        Editable
      </div>
      {editor && <BubbleMenu editor={editor} tippyOptions={{ duration: 100 }}>
        <button
          onClick={() => editor.chain().focus().toggleBold().run()}
          className={editor.isActive('bold') ? 'is-active' : ''}
        >
          bold
        </button>
        <button
          onClick={() => editor.chain().focus().toggleItalic().run()}
          className={editor.isActive('italic') ? 'is-active' : ''}
        >
          italic
        </button>
        <button
          onClick={() => editor.chain().focus().toggleStrike().run()}
          className={editor.isActive('strike') ? 'is-active' : ''}
        >
          strike
        </button>
      </BubbleMenu>}
      <EditorContent editor={editor} />
    </>
  )
}
.ProseMirror {
  > * + * {
    margin-top: 0.75em;
  }
}

input[type="checkbox"] {
  margin-right: 8px;
}

下载教程 Demo

本教程Demo的源码点击这里下载,Tiptap Demo,下载完成后运行npm i初始化依赖包。