Vue.js - 富文本编辑器Tiptap使用详解1(安装与基础配置)
作者:hangge | 2026-02-10 08:42
Tiptap 是一个基于 ProseMirror 的无渲染富文本编辑器,专为 Vue、React 等现代前端框架设计。与传统的富文本编辑器不同,Tiptap 不提供预定义的 UI 组件,而是将完整的 UI 控制权交给开发者,这使得定制化编辑器界面变得异常灵活。本文首先介绍如何在 Vue 2 项目中安装配置 Tiptap。
(2)各依赖的功能如下:
(1)下面代码演示如何在 Vue 2 中创建 Editor 实例并渲染编辑区域(使用 StarterKit):
(2)运行后可用看到编辑区域显示出我们预设的文字。

(2)运行程序可用看到编辑器上面出现工具栏,点击相关按钮即可实现对应快捷操作。
一、安装与基础配置
1,快速安装
(1)进入 Vue 项目目录,执行如下命令安装 Tiptap 依赖:
npm install @tiptap/vue-2 @tiptap/core @tiptap/starter-kit @tiptap/extension-link @tiptap/pm
(2)各依赖的功能如下:
- @tiptap/vue-2:Vue2 的组件包装器(让我们在 Vue 2 中使用 EditorContent 等)。
- @tiptap/core:编辑器核心:
- @tiptap/starter-kit:一组常用扩展(段落、粗体/斜体、列表、undo/redo、dropcursor 等),适合快速启动。
- @tiptap/pm:Tiptap 提供的 ProseMirror 包的打包版,能避免 ProseMirror 版本冲突(在某些包管理器或环境下显得重要)。若遇到缺失 ProseMirror 相关依赖报错,安装此包通常能解决问题
2,最小可运行示例
<template>
<div class="basic-tiptap">
<!-- EditorContent 负责渲染 contenteditable 区域 -->
<editor-content :editor="editor" />
</div>
</template>
<script>
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
import { EditorContent } from '@tiptap/vue-2'
export default {
name: 'BasicTiptap',
components: { EditorContent },
data() {
return { editor: null }
},
mounted() {
// 在 mounted 创建 Editor 实例并传入扩展与初始内容
this.editor = new Editor({
extensions: [ StarterKit ],
content: `<h2>欢迎访问hangge.com</h2>
<p>这是一个最小的示例。</p>`
})
},
beforeDestroy() {
// 组件销毁前一定清理 editor 实例,避免内存泄漏
if (this.editor) this.editor.destroy()
}
}
</script>
<style scoped>
.basic-tiptap {
border: 1px solid #e6e6e6;
padding: 12px;
border-radius: 6px;
min-height: 180px;
}
</style>
(2)运行后可用看到编辑区域显示出我们预设的文字。

(3)点击该区域可用进入编辑状态,此时我们可用输入、选择文字并使用浏览器快捷键,如:Ctrl + B 加粗文本、Ctrl + I 将文本设置为斜体、Ctrl + U 文本添加下划线。

3,带工具栏的基础示例
(1)通常来说我们编辑器上面还需要有一个工具栏,而不是只用快捷键)。下面示例在最小示例基础上增加了常见按钮(加粗、斜体、下划线、中划线、无序列表、有序列表、插入链接、移除链接)。
提示:由于 Tiptap 是“headless”编辑器(它不自带 UI),因此按钮、菜单栏等需要我们自己实现(像下面这样在 Vue 中调用 editor.chain()...run())。若按钮样式需求复杂,可用图标库(FontAwesome)或自行样式化。
<template>
<div class="editor-wrap">
<div class="toolbar" role="toolbar" aria-label="Editor toolbar">
<button
:class="{ active: isActive('bold') }"
@click="toggleBold"
:title="'加粗 (Ctrl/Cmd+B)'"
>B</button>
<button
:class="{ active: isActive('italic') }"
@click="toggleItalic"
:title="'斜体 (Ctrl/Cmd+I)'"
>I</button>
<button
:class="{ active: isActive('underline') }"
@click="toggleUnderline"
:title="'下划线 (Ctrl/Cmd+U)'"
>U</button>
<button
:class="{ active: isActive('strike') }"
@click="toggleStrike"
:title="'删除线'"
>S</button>
<button
:class="{ active: isActive('bulletList') }"
@click="toggleBulletList"
:title="'项目符号列表'"
>• List</button>
<button
:class="{ active: isActive('orderedList') }"
@click="toggleOrderedList"
:title="'编号列表'"
>1. List</button>
<button @click="addLink" title="插入链接">🔗</button>
<button @click="removeLink" title="移除链接">✖️🔗</button>
</div>
<editor-content :editor="editor" class="editor-content" />
</div>
</template>
<script>
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
import Link from '@tiptap/extension-link'
import Underline from '@tiptap/extension-underline' // 可选:若 StarterKit 未包含
import Strike from '@tiptap/extension-strike' // 若需要删除线(StarterKit 通常包含)
import { EditorContent } from '@tiptap/vue-2'
export default {
name: 'EditorFormatting',
components: { EditorContent },
data() {
return { editor: null }
},
mounted() {
this.editor = new Editor({
extensions: [ StarterKit, Link, Underline, Strike ],
content: `<h2>欢迎访问hangge.com</h2>
<p>这是一个最小的示例。这是一个最小的示例。这是一个最小的示例。这是一个最小的示例。</p>
<p>列表1</p>
<p>列表2</p>
<p>列表3</p>
<p>列表1</p>
<p>列表2</p>
<p>列表3</p>`
// onUpdate / onTransaction 可在此加入,但示例以最小化为主
})
},
methods: {
/* 文本样式命令(使用链式 API 并 focus() 保证焦点) */
toggleBold() { this.editor.chain().focus().toggleBold().run() },
toggleItalic() { this.editor.chain().focus().toggleItalic().run() },
toggleUnderline() { this.editor.chain().focus().toggleUnderline().run() },
toggleStrike() { this.editor.chain().focus().toggleStrike().run() },
/* 列表 */
toggleBulletList() { this.editor.chain().focus().toggleBulletList().run() },
toggleOrderedList() { this.editor.chain().focus().toggleOrderedList().run() },
/* 链接操作:插入或移除 */
addLink() {
const url = prompt('请输入链接 URL(包含 http:// 或 https://)')
if (!url) return
// extendMarkRange 可以确保扩展当前选区的 mark 范围(便于整段变为 link)
this.editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run()
},
removeLink() {
this.editor.chain().focus().unsetLink().run()
},
/* 判断当前格式是否激活(用于按钮高亮) */
isActive(name, attrs = {}) {
return this.editor && this.editor.isActive(name, attrs)
}
},
beforeDestroy() {
if (this.editor) this.editor.destroy()
}
}
</script>
<style scoped>
.editor-wrap { border: 1px solid #ddd; border-radius:6px; }
.toolbar { padding:8px; background:#fafafa; display:flex; gap:6px; flex-wrap:wrap; }
.toolbar button { padding:6px 8px; border:1px solid #eaeaea;
background:white; border-radius:4px; cursor:pointer; }
.toolbar button.active { background:#e6f7ff; border-color:#91d5ff; font-weight:600; }
.editor-content { min-height:200px; padding:12px; }
</style>
(2)运行程序可用看到编辑器上面出现工具栏,点击相关按钮即可实现对应快捷操作。

全部评论(0)