Movatterモバイル変換


[0]ホーム

URL:


Vue3 + Tiptap 从零打造富文本编辑器(含实时协作、快捷键、扩展全解析)

最新推荐文章于 2025-10-26 00:36:01 发布
原创最新推荐文章于 2025-10-26 00:36:01 发布·2.1k 阅读
· 27
· 41·
CC 4.0 BY-SA版权
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。
该文章已生成可运行项目,

目录

🧰 技术栈

📦 所需依赖

📁 文件结构

🧱 编辑器组件实现(components/Editor.vue)

✨ 常用操作指令

🧠 小贴士

🧩 Tiptap 扩展功能使用说明(含快捷键与命令)

🔹 StarterKit(基础功能集)

🔹 Link(链接)

🔹 Table(表格)

🔹 CodeBlockLowlight(代码块 + 语法高亮)

🔹 Placeholder(占位提示)

🔹 Image(图片上传)

🔹 自定义 Attachment(附件上传)

tiptap collaborative 实时协作

网络实时通信

WebSocket 推荐

WebSocket 后端

多个服务器

显示光标

离线支持

🔗 推荐链接

✅ 总结


本文是针对零基础前端开发者撰写,目的是快速上手并集成一个功能完整的富文本编辑器(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 等),可以继续在此格式基础上扩展。

    🔗 推荐链接

    ✅ 总结

    本文总结了一个基于 Vue3 + Tiptap 的富文本编辑器完整实现过程,涵盖依赖安装、扩展配置、编辑器初始化与常用操作,适合新手开发者快速上手。如果你希望快速搭建一个功能完整的编辑器,完全可以直接复制本文结构并根据需求调整内容。

    本文章已经生成可运行项目
    关注博主即可阅读全文
    确定要放弃本次机会?
    福利倒计时
    ::

    立减 ¥

    普通VIP年卡可用
    立即使用
    30 条评论您还未登录,请先登录后发表或查看评论

    博客等级

    码龄4年
    92
    原创
    1812
    点赞
    1429
    收藏
    1793
    粉丝
    关注
    私信

    更多优质【一键运行】博文

    查看更多查看更多

    热门文章

    分类专栏

    展开全部收起

    上一篇:
    前端开发者快速理解Spring Boot项目指南
    下一篇:
    使用HTML5 Canvas实现前端图片分辨率压缩(附完整代码)

    最新评论

    大家在看

    最新文章

    2025

    目录

    展开全部

    收起

    目录

    评论 30
    被折叠的  条评论为什么被折叠?到【灌水乐园】发言
    查看更多评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝规则
    hope_wisdom
    发出的红包

    打赏作者

    像素笔记

    你的鼓励将是我创作的最大动力

    ¥1¥2¥4¥6¥10¥20
    扫码支付:¥1
    获取中
    扫码支付

    您的余额不足,请更换扫码支付或充值

    打赏作者

    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值

    [8]ページ先頭

    ©2009-2025 Movatter.jp