目录
🧱 编辑器组件实现(components/Editor.vue)
🔹 CodeBlockLowlight(代码块 + 语法高亮)
本文是针对零基础前端开发者撰写,目的是快速上手并集成一个功能完整的富文本编辑器(Tiptap)到你的 Vue 项目中。
🧰 技术栈
Vue 3 +
<script setup>Tiptap(基于 ProseMirror)
多种 Tiptap 插件(Extension)支持
📦 所需依赖
npm install @tiptap/vue-3 @tiptap/starter-kit \ @tiptap/extension-link \ @tiptap/extension-table \ @tiptap/extension-table-row \ @tiptap/extension-table-cell \ @tiptap/extension-table-header \ @tiptap/extension-placeholder \ @tiptap/extension-code-block-lowlight \ @tiptap/extension-image \ @tiptap/extension-character-count \ lowlight📁 文件结构
src/├─ components/│ └─ Editor.vue # 编辑器组件└─ App.vue🧱 编辑器组件实现(components/Editor.vue)
<template> <editor-content :editor="editor" class="editor" /></template><script setup>import { onBeforeUnmount } from 'vue'import { Editor, EditorContent } from '@tiptap/vue-3'import StarterKit from '@tiptap/starter-kit'import Link from '@tiptap/extension-link'import Table from '@tiptap/extension-table'import TableRow from '@tiptap/extension-table-row'import TableCell from '@tiptap/extension-table-cell'import TableHeader from '@tiptap/extension-table-header'import Placeholder from '@tiptap/extension-placeholder'import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight'import { lowlight } from 'lowlight/lib/common'import Image from '@tiptap/extension-image'import CharacterCount from '@tiptap/extension-character-count'const editor = new Editor({ extensions: [ StarterKit, Link, Placeholder.configure({ placeholder: '请输入内容…' }), Table.configure({ resizable: true }), TableRow, TableCell, TableHeader, CodeBlockLowlight.configure({ lowlight }), Image, CharacterCount.configure({ limit: 500 }), ], content: '<p>Hello Tiptap!</p>',})onBeforeUnmount(() => { editor.destroy()})</script><style scoped>.editor { border: 1px solid #ccc; padding: 16px; border-radius: 8px; min-height: 200px;}</style>✨ 常用操作指令
获取 HTML 内容:
editor.getHTML()获取 JSON 内容:
editor.getJSON()执行命令示例(如设置为加粗):
editor.commands.toggleBold()🧠 小贴士
所有 Extension 都可以配置和拓展,官方文档中提供了详细 API。
菜单栏需要你自行实现,可以通过组合
editor.commands来制作按钮。可自定义 CSS 样式,支持暗色模式、响应式布局等。
🧩 Tiptap 扩展功能使用说明(含快捷键与命令)
以下内容将详细列出各个 Tiptap 扩展的使用方式,包括:
如何引入
如何注册(放进 extensions)
快捷键(如有)
使用 editor.commands 如何触发
🔹 StarterKit(基础功能集)
引入:
import StarterKit from '@tiptap/starter-kit'注册:
extensions: [ StarterKit ]快捷键(默认):
加粗:
Mod-b斜体:
Mod-i标题:
Ctrl-Alt-1~6列表:
Shift-Ctrl-8/9
命令示例:
editor.commands.toggleBold()editor.commands.toggleItalic()editor.commands.toggleHeading({ level: 2 })editor.commands.toggleBulletList()🔹 Link(链接)
引入:
import Link from '@tiptap/extension-link'注册:
extensions: [ Link.configure({ openOnClick: true }) ]快捷键:无默认
命令示例:
editor.commands.setLink({ href: 'https://example.com' })editor.commands.unsetLink()🔹 Table(表格)
引入:
import Table from '@tiptap/extension-table'import TableRow from '@tiptap/extension-table-row'import TableHeader from '@tiptap/extension-table-header'import TableCell from '@tiptap/extension-table-cell'注册:
extensions: [ Table.configure({ resizable: true }), TableRow, TableHeader, TableCell,]快捷键:无默认
命令示例:
editor.commands.insertTable({ rows: 3, cols: 3 })editor.commands.addColumnAfter()editor.commands.deleteTable()🔹 CodeBlockLowlight(代码块 + 语法高亮)
引入:
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight'import { lowlight } from 'lowlight/lib/common'注册:
extensions: [ CodeBlockLowlight.configure({ lowlight }),]快捷键:
`Ctrl + Shift + ``
命令示例:
editor.commands.toggleCodeBlock()🔹 Placeholder(占位提示)
引入:
import Placeholder from '@tiptap/extension-placeholder'注册:
extensions: [ Placeholder.configure({ placeholder: '请输入内容…' })]快捷键:无
命令示例:无,主要是展示效果
🔹 Image(图片上传)
引入:
import Image from '@tiptap/extension-image'注册:
extensions: [ Image ]快捷键:无
命令示例:
editor.commands.setImage({ src: 'https://example.com/image.jpg' })通常结合
<input type="file">使用,将图片上传到服务器后获取链接插入。
🔹 自定义 Attachment(附件上传)
Tiptap 没有内建“附件”类型,可自定义扩展:
引入(自定义 Node):
async handleFileUpload(e) { const file = e.target.files[0]; if (!file) return; try { // 1. 上传文件到服务器(假设 uploadImage 支持所有类型或调整为通用上传函数) const url = await this.uploadImage(file); // 2. 根据文件类型插入内容 if (file.type.startsWith('image/')) { // 插入图片 this.editor.chain().focus().setImage({ src: url }).run(); } else { // 非图片类型插入“附件”文本(可带链接) this.editor.chain().focus().insertContent('附件').run(); // 如需插入链接:this.editor.chain().focus().insertContent(`<a href="${url}">附件</a>`).run(); } } catch (error) { console.error("上传失败:", error); alert("上传失败,请重试"); } finally { e.target.value = null; }}快捷键:无
命令示例:
editor.commands.insertContent({ type: 'attachment', attrs: { href: 'https://example.com/file.pdf', filename: '报告文件.pdf', },})上传方式与图片类似,使用 file input 或拖拽上传后插入链接。
tiptap collaborative 实时协作
tiptap 支持实时协作、让不同设备之间的同步和离线工作。通过与 Y.js 配合使用无需多少代码即可实现多人在线实时协作,不过在大部分的实践工作中,实时协作并不是一个强需求。
网络实时通信
WebRTC仅使用服务器让各个客户端(浏览器)击行相互通讯。服务器并不参与数据的传输。
安装依赖项:
npm install @tiptap/extension-collaboration yjs y-webrtc y-prosemirror然后创建一个 Y 文档,并注册到 Tiptap:
import { WebrtcProvider } from 'y-webrtc'// A new Y documentconst ydoc = new Y.Doc()// Registered with a WebRTC providerconst provider = new WebrtcProvider('example-document', ydoc)const editor = new Editor({ extensions: [ StarterKit.configure({ // The Collaboration extension comes with its own history handling history: false, }), // Register the document with Tiptap Collaboration.configure({ document: ydoc, }), ],})到此为止你就可以让不同的用户进行实时协作了,它是如何运行的呢?WebRTC程序通过公共服务器将客户端连接在一起,服务器并不同步实际的更改,然而这个也有两个缺点。
1,浏览器拒绝连接太多客户端,对于同一文档中超过 100+ 个并发客户端,它不能很好的支持。
2,服务器没有参与文档记录的更改,因为WebRTC信令服务器不会收到更改,因此不知道文档中的内容。
如果你想更深入地研究,请前往GitHub上的Y WebRTC存储库
WebSocket 推荐
对于大多数情况,tiptap建议使用 WebSocket ,因为它更灵活,也可以很好地扩展。为了更容易使用,tiptap发布了Hocuspocus作为Tiptap的官方后端程序。
对于客户端示例几乎相同,只不过驱动程序不同。首先,让我们安装依赖项:
npm install @tiptap/extension-collaboration @hocuspocus/provider y-prosemirror然后向 Tiptap 注册 WebSocket 供应程序:
import { Editor } from '@tiptap/core'import StarterKit from '@tiptap/starter-kit'import Collaboration from '@tiptap/extension-collaboration'import { HocuspocusProvider } from '@hocuspocus/provider'// Set up the Hocuspocus WebSocket providerconst provider = new HocuspocusProvider({ url: 'ws://127.0.0.1:1234', name: 'example-document',})const editor = new Editor({ extensions: [ StarterKit.configure({ // The Collaboration extension comes with its own history handling history: false, }), // Register the document with Tiptap Collaboration.configure({ document: provider.document, }), ],})如你所见此示例不是开箱即用的。它需要配置为与WebSocket服务器通信,因此需要安装WebSocket 后端程序Hocuspocus。
WebSocket 后端
为了使服务器部分尽可能简单,tiptap提供了一个node.js的服务器包 Hocuspocus。它是一个灵活的 Node.js 包,可用于构建后端。
下面的命令用来启动这个服务:
npx @hocuspocus/cli --port 1234 --sqlite运行 Hocuspocus 命令行,启动侦听1234端口并将更改存储在内存中(一旦停止命令,它就会消失),输出如下所示:
Hocuspocus v1.0.0 running at:> HTTP: http://127.0.0.1:1234> WebSocket: ws://127.0.0.1:1234Ready.尝试在浏览器中打开 http://127.0.0.1:1234 网址,如果一切运行正常,你应该会看到一个纯文本。
然后返回 Tiptap 编辑器并F5刷新网页,它将连接到 Hocuspocus WebSocket 服务器,这时就可以与其他用户进行实时协作了。
多个服务器
你可以注册多个服务器保证服务的稳定,当一个服务器宕机客户端将连接另外一个服务器
new WebrtcProvider('example-document', ydoc)new HocuspocusProvider({ url: 'ws://127.0.0.1:1234', name: 'example-document', document: ydoc,})显示光标
当多个人进行在线编辑,你可以设置每个人的昵称显示在编辑器光标位置
import { Editor } from '@tiptap/core'import StarterKit from '@tiptap/starter-kit'import Collaboration from '@tiptap/extension-collaboration'import CollaborationCursor from '@tiptap/extension-collaboration-cursor'import { HocuspocusProvider } from '@hocuspocus/provider'// Set up the Hocuspocus WebSocket providerconst provider = new HocuspocusProvider({ url: 'ws://127.0.0.1:1234', name: 'example-document',})const editor = new Editor({ extensions: [ StarterKit.configure({ // The Collaboration extension comes with its own history handling history: false, }), Collaboration.configure({ document: provider.document, }), // Register the collaboration cursor extension CollaborationCursor.configure({ provider: provider, user: { name: 'Cyndi Lauper', color: '#f783ac', }, }), ],})离线支持
基于Y IndexedDB 你可以实现关闭浏览器后所有更改都将存储在浏览器中,下次联机时,WebSocket 提供程序将尝试查找连接并最终同步更改。
如需添加更多扩展(如任务列表、缩进、emoji 等),可以继续在此格式基础上扩展。
🔗 推荐链接
- tiptap 自定义扩展 | 抠丁客
ProseMirror 引擎:ProseMirror
✅ 总结
本文总结了一个基于 Vue3 + Tiptap 的富文本编辑器完整实现过程,涵盖依赖安装、扩展配置、编辑器初始化与常用操作,适合新手开发者快速上手。如果你希望快速搭建一个功能完整的编辑器,完全可以直接复制本文结构并根据需求调整内容。























5321


























