Skip to content

RichTextEditor ​

带工具栏、气泡菜单和页脚的基础富文本编辑器。所有子组件挂在 RichTextEditor 上,模板里可以直接写 <RichTextEditor.Bold />。

在线演示 ​

variant

视觉变体 ​

variant="default"

variant="subtle"

variant="compact"

基本用法 ​

vue
<script setup lang="ts">
import StarterKit from "@tiptap/starter-kit";
import TextAlign from "@tiptap/extension-text-align";
import Placeholder from "@tiptap/extension-placeholder";
import { useEditor } from "@tiptap/vue-3";

import { CodeBlock, Link, RichTextEditor } from "@/components/editor";
import "@/components/editor/style.css";

const editor = useEditor({
  content: "<p>你好</p>",
  extensions: [
    StarterKit.configure({ link: false, codeBlock: false }),
    Link,
    CodeBlock,
    TextAlign.configure({ types: ["heading", "paragraph"] }),
    Placeholder.configure({ placeholder: "开始输入…" }),
  ],
});
</script>

<template>
  <RichTextEditor :editor="editor" variant="default">
    <RichTextEditor.Toolbar sticky :sticky-offset="0">
      <RichTextEditor.ControlsGroup>
        <RichTextEditor.Bold />
        <RichTextEditor.Italic />
        <RichTextEditor.Underline />
        <RichTextEditor.Strikethrough />
        <RichTextEditor.Code />
      </RichTextEditor.ControlsGroup>

      <RichTextEditor.ControlsGroup>
        <RichTextEditor.H1 />
        <RichTextEditor.H2 />
        <RichTextEditor.H3 />
        <RichTextEditor.Blockquote />
        <RichTextEditor.Hr />
      </RichTextEditor.ControlsGroup>

      <RichTextEditor.ControlsGroup>
        <RichTextEditor.BulletList />
        <RichTextEditor.OrderedList />
        <RichTextEditor.TaskList />
        <RichTextEditor.CodeBlock />
      </RichTextEditor.ControlsGroup>

      <RichTextEditor.ControlsGroup>
        <RichTextEditor.AlignLeft />
        <RichTextEditor.AlignCenter />
        <RichTextEditor.AlignRight />
        <RichTextEditor.AlignJustify />
      </RichTextEditor.ControlsGroup>

      <RichTextEditor.ControlsGroup>
        <RichTextEditor.Highlight />
        <RichTextEditor.Subscript />
        <RichTextEditor.Superscript />
        <RichTextEditor.ClearFormatting />
      </RichTextEditor.ControlsGroup>

      <RichTextEditor.ControlsGroup>
        <RichTextEditor.Link />
        <RichTextEditor.Unlink />
      </RichTextEditor.ControlsGroup>

      <RichTextEditor.ControlsGroup>
        <RichTextEditor.Undo />
        <RichTextEditor.Redo />
      </RichTextEditor.ControlsGroup>
    </RichTextEditor.Toolbar>

    <RichTextEditor.Content class="min-h-64">
      <RichTextEditor.BubbleMenu :editor="editor ?? null" />
    </RichTextEditor.Content>

    <RichTextEditor.Footer show-word-count sticky />
  </RichTextEditor>
</template>

Props ​

RichTextEditor ​

属性类型默认说明
editorEditor | null | undefined—useEditor() 返回的实例
variant"default" | "subtle" | "compact""default"视觉变体
editablebooleantruefalse 时隐藏工具栏并切只读
labelsPartial<RichTextEditorLabels>—覆盖文案
iconsPartial<RichTextEditorIcons>—覆盖图标组件
属性类型说明
stickyboolean吸顶
stickyOffsetnumber | string吸顶距离,默认 0

Footer 额外支持 showWordCount、wordCountFormatter: (info) => string、wordCountClassName。

Content / Control / ControlsGroup ​

Content 接受 class;Control 是自定义控件的基座:

vue
<RichTextEditor.Control
  :active="editor?.isActive('strike')"
  aria-label="删除线"
  @click="editor?.chain().focus().toggleStrike().run()"
>
  <MyIcon />
</RichTextEditor.Control>
属性类型说明
activeboolean高亮状态
disabledboolean禁用

其余属性(aria-label、class、事件)直接透传到按钮。

控件 ​

控件需要的扩展
Bold Italic Strikethrough CodeStarterKit
Underline@tiptap/extension-underline
Highlight需要 Highlight(多色需 multicolor: true)
Subscript Superscript对应扩展
H1–H6 Blockquote Hr BulletList OrderedList CodeBlockStarterKit
TaskListTaskList + TaskItem
AlignLeft AlignCenter AlignRight AlignJustifyTextAlign
Link Unlink组件自带的 Link(已配置 openOnClick: false)
Undo RedoStarterKit 的 history
ClearFormatting无

没有注册对应扩展时,控件会静默失效或显示为不可用状态,不会抛错。

气泡菜单 ​

选中文字后浮出:加粗 / 斜体 / 下划线 / 删除线 / 代码、文字颜色、背景色、链接、清除格式。在代码块内会切换成语言选择器。

vue
<RichTextEditor.Content>
  <RichTextEditor.BubbleMenu :editor="editor ?? null" />
</RichTextEditor.Content>

也可以把气泡菜单放到页面任意位置,只需要传 editor。

链接 ​

RichTextEditor.Link 打开 reka-ui 的 Popover:输入地址、回车确认、Mod-k 也可以触发。Link 扩展由组件包导出,配置已处理:

ts
import { Link } from "@/components/editor";

Link.configure({ openOnClick: false, autolink: true });

字数统计 ​

vue
<RichTextEditor.Footer
  show-word-count
  :word-count-formatter="({ words, characters }) => `${characters} 字符 / ${words} 词`"
/>

自定义控件 ​

ts
import { createControl } from "@/components/editor";

export const HighlightControl = createControl({
  label: "highlightControlLabel",   // keyof RichTextEditorLabels
  iconKey: "highlightControlIcon",  // keyof RichTextEditorIcons
  isActive: { name: "highlight" },
  isDisabled: (editor) => editor.isActive("codeBlock"),
  operation: { name: "toggleHighlight" },
});
字段说明
label文案键,从 labels 上下文取值
iconKey图标键,从 icons 上下文取值
isActive{ name, attributes? } 或 { attrs },也可以用 editor.isActive 的判断方式
isDisabled(editor) => boolean,可选
operation{ name, attributes? },调用 editor.chain().focus()[name](attributes).run()

返回值是普通 Vue 组件,放进 <RichTextEditor.ControlsGroup> 即可。注意它是通过 operation.name 动态派发链式命令的,name 必须是 Tiptap 命令名(如 toggleHighlight)。