Tiptap(基于 Prosemirror)vs TinyMCE:哪個更適合你的技術棧?

在這之前,先來介紹一下 ProseMirror


1. ProseMirror 是底層內核

  • 定位:一個強大的 富文本編輯框架/引擎,不是一個成品編輯器。

  • 作者:Marijn Haverbeke(CodeMirror 作者)。

  • 核心思想

    • schema(模式) 定義文檔結構(節點、marks、attributes)。
    • 每個操作(加粗、插入段落)都是 transaction(事務)
    • 提供 collab(協作)、history、markdown 解析、插件系統 等能力。
  • 問題:API 很底層、復雜(寫一個“加粗按鈕”就需要懂 state/transaction/command)。


2. Tiptap 是 ProseMirror 的高級封裝

  • 定位:一個 基于 ProseMirror 的現代編輯器框架

  • 特點

    • 提供了更友好的 API(例如 editor.chain().focus().toggleBold().run(),不用直接操作 transaction)。
    • 內置常用擴展(StarterKit:paragraph、heading、bold、italic、list、code 等)。
    • 框架無關(React、Vue、Svelte、純 JS 都能用)。
    • 社區活躍,擴展豐富(Mention、SlashCommand、Table、Collaboration 等)。
    • 專門為現代 Web 應用優化(支持移動端、協同編輯、富 UI 集成)。

3. 核心區別

對比點ProseMirrorTiptap
定位底層引擎 / 框架高級封裝 / 開發者友好的框架
難度高(API 底層,文檔晦澀)中等(鏈式調用,擴展豐富)
功能一切都要自己實現內置 StarterKit,常用功能即插即用
UI沒有(自己寫)沒有默認 UI,但社區有現成擴展
靈活性無限靈活靈活 + 更高生產力
適合人群想深度定制、寫自己編輯器內核的人想快速落地 Notion/Google Docs 類應用的人

4. 關系總結

  • ProseMirror = 編輯器的內核(底層引擎)。
  • Tiptap = 基于 ProseMirror 的開發框架(更好用的外殼)。
  • 你用 Tiptap,其實是在用 ProseMirror,只不過被封裝了一層,更易上手。
  • 如果你遇到 Tiptap 沒提供的功能,最終可能需要寫 ProseMirror 插件/擴展

  • ProseMirror vs Tiptap 的架構圖:

 **ProseMirror vs Tiptap 的架構圖**


下面,回歸正題:

一、本文將對比 Tiptap EditorTinyMCE,從技術架構、功能、擴展性、適用場景等方面做出分析。

1. 技術架構

  • Tiptap Editor

    • 基于 ProseMirror,是一個現代化的富文本編輯框架。
    • 完全用 JavaScript/TypeScript 編寫,UI 無關(React、Vue、Svelte 都能集成)。
    • 更偏向“編輯器框架”,需要開發者配置和擴展。
  • TinyMCE

    • 歷史悠久的傳統富文本編輯器(WYSIWYG),早期就用于網頁中的文字編輯。
    • 內置 UI(工具欄、菜單)和功能較多,開箱即用。
    • 偏向于“現成的產品”,即插即用。

2. 功能特性

  • Tiptap

    • 靈活度高,可以完全自定義編輯體驗(例如 Notion、Slack、Linear 都是基于 ProseMirror/Tiptap)。
    • 支持協同編輯(結合 yjs/y-websocket)。
    • 插件體系強大(markdown、mention、slash command、自定義節點)。
    • 原生支持移動端、現代前端框架。
    • UI/菜單需要自己實現或用社區擴展。
  • TinyMCE

    • 開箱即用的傳統功能:字體、顏色、表格、圖片上傳、對齊、列表等等。
    • 插件體系完善,但更多是 WYSIWYG 的擴展(如 word count、spellcheck)。
    • 有商業版(帶更多企業功能,如 MS Word/Google Docs 級別的協作和導出)。
    • 移動端體驗不如 Tiptap,但兼容性很好。

3. 學習曲線

  • Tiptap:需要較強的前端開發能力,理解 ProseMirror schema、node/mark 才能發揮最大價值。
  • TinyMCE:學習成本低,只要引入腳本即可用,配置主要是工具欄和插件。

4. 可擴展性 & 自定義

  • Tiptap

    • 高度可定制,可以實現類似 Notion、Coda、Obsidian 那種 block-based 編輯器。
    • 自定義節點(自定義組件、Vue/React 元素嵌入)非常靈活。
    • 對現代 web app(SaaS、在線文檔)很適合。
  • TinyMCE

    • 自定義能力有限,雖然可以寫插件,但核心思想還是“富文本編輯器”。
    • 適合標準化的富文本場景(CMS、論壇、評論系統)。

5. 使用場景

  • 選擇 Tiptap

    • 你在做一個 現代 SaaS/協作工具(比如 Notion、文檔協作、知識庫)。
    • 需要 協作編輯自定義 block/組件
    • 前端團隊實力較強,可以投入時間定制。
  • 選擇 TinyMCE

    • 你在做 CMS、表單、企業后臺,只需要 標準富文本(發文章、加粗、插入表格圖片)。
    • 團隊希望 快速上線,不想花時間定制編輯器。
    • 用戶群體對“Word 類似體驗”有需求。

6. 對比總結

特性Tiptap Editor (ProseMirror)TinyMCE
定位編輯器框架 (現代、靈活)成品富文本編輯器 (傳統、開箱即用)
UI/工具欄需要自己做 / 社區擴展內置完善工具欄
功能擴展無限靈活,可嵌入 React/Vue 組件主要是 WYSIWYG 擴展
協同編輯支持 (yjs 集成)商業版支持
移動端體驗優秀一般
學習成本高(要理解 ProseMirror)低(配置工具欄即可)
最佳適用場景Notion/知識庫/協作編輯CMS/后臺文章/傳統富文本

二、 下面將提供 Tiptap (Vue 3)TinyMCE (純 HTML/JS) 的最小可運行示例


1. Tiptap (Vue 3 示例)

<template><div><EditorContent :editor="editor" class="border p-3 min-h-[200px]" /></div>
</template><script setup>
import { ref, onBeforeUnmount } from "vue"
import { EditorContent, useEditor } from "@tiptap/vue-3"
import StarterKit from "@tiptap/starter-kit"const editor = useEditor({extensions: [StarterKit],content: "<p>Hello <b>Tiptap</b> 🚀</p>",
})onBeforeUnmount(() => {editor?.destroy()
})
</script><style>
.ProseMirror {min-height: 200px;outline: none;
}
</style>

👉 特點:

  • 這是最小示例,只帶 StarterKit(加粗、斜體、標題、列表、代碼等基礎功能)。
  • 你可以往里加插件,比如 mention、slash command、表格、Markdown。
  • 沒有默認工具欄,要自己寫按鈕控制(高度可定制)。

2. TinyMCE (純 HTML/JS 示例)

<!DOCTYPE html>
<html>
<head><script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/6/tinymce.min.js"></script>
</head>
<body><textarea id="editor">Hello <b>TinyMCE</b> ?</textarea><script>tinymce.init({selector: '#editor',height: 300,plugins: 'lists link image table code',toolbar: 'undo redo | bold italic underline | bullist numlist | link image table | code',});</script>
</body>
</html>

👉 特點:

  • 一引入就能用,帶完整工具欄。
  • 插件和配置非常像傳統富文本(Word)。
  • 如果要集成到 Vue/React,也有官方包,但核心就是 tinymce.init

📌 總結:

  • Tiptap → 需要開發者寫 UI,但能做出 Notion/Slack/協作文檔 的感覺。
  • TinyMCE → 一步到位,像 Word 編輯器,但定制自由度沒那么高。

三、下面示例將完善一下工具欄

Tiptap (Vue 3 + 工具欄 示例)

<template><div class="editor"><!-- 工具欄 --><div class="toolbar"><button @click="toggleBold" :class="{ active: editor.isActive('bold') }">B</button><button @click="toggleItalic" :class="{ active: editor.isActive('italic') }">I</button><button @click="setHeading(1)" :class="{ active: editor.isActive('heading', { level: 1 }) }">H1</button><button @click="setHeading(2)" :class="{ active: editor.isActive('heading', { level: 2 }) }">H2</button><button @click="toggleBulletList" :class="{ active: editor.isActive('bulletList') }">? List</button><button @click="toggleOrderedList" :class="{ active: editor.isActive('orderedList') }">1. List</button><button @click="toggleCodeBlock" :class="{ active: editor.isActive('codeBlock') }">Code</button></div><!-- 編輯區 --><EditorContent :editor="editor" class="editor-content" /></div>
</template><script setup>
import { onBeforeUnmount } from "vue"
import { EditorContent, useEditor } from "@tiptap/vue-3"
import StarterKit from "@tiptap/starter-kit"const editor = useEditor({extensions: [StarterKit],content: "<p>Hello <b>Tiptap</b> with Toolbar 🚀</p>",
})onBeforeUnmount(() => {editor?.destroy()
})// 工具欄方法
const toggleBold = () => editor.chain().focus().toggleBold().run()
const toggleItalic = () => editor.chain().focus().toggleItalic().run()
const setHeading = (level) => editor.chain().focus().toggleHeading({ level }).run()
const toggleBulletList = () => editor.chain().focus().toggleBulletList().run()
const toggleOrderedList = () => editor.chain().focus().toggleOrderedList().run()
const toggleCodeBlock = () => editor.chain().focus().toggleCodeBlock().run()
</script><style>
.editor {border: 1px solid #ccc;border-radius: 6px;padding: 8px;max-width: 600px;margin: auto;
}.toolbar {border-bottom: 1px solid #ddd;padding-bottom: 6px;margin-bottom: 6px;
}.toolbar button {margin-right: 6px;padding: 4px 8px;border: 1px solid #ccc;background: white;cursor: pointer;border-radius: 4px;
}.toolbar button.active {background: #007bff;color: white;
}.editor-content {min-height: 200px;padding: 6px;outline: none;
}
</style>

👉 這樣效果就是:

  • 上面一排按鈕(加粗、斜體、H1、H2、列表、代碼塊)。
  • 點擊按鈕就能直接控制編輯區。
  • 你可以繼續擴展,比如 插入圖片、mention、slash command,靈活度很高。

  • React + Tiptap + 工具欄示例,方便和 Vue 版本對比。

Tiptap (React + 工具欄 示例)

import React, { useEffect } from "react"
import { EditorContent, useEditor } from "@tiptap/react"
import StarterKit from "@tiptap/starter-kit"
import "./editor.css"  // 樣式寫在單獨的 css 文件const TiptapEditor = () => {const editor = useEditor({extensions: [StarterKit],content: "<p>Hello <b>Tiptap</b> with Toolbar 🚀</p>",})useEffect(() => {return () => editor?.destroy()}, [editor])if (!editor) return nullreturn (<div className="editor">{/* 工具欄 */}<div className="toolbar"><button onClick={() => editor.chain().focus().toggleBold().run()}className={editor.isActive("bold") ? "active" : ""}>B</button><button onClick={() => editor.chain().focus().toggleItalic().run()}className={editor.isActive("italic") ? "active" : ""}>I</button><button onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}className={editor.isActive("heading", { level: 1 }) ? "active" : ""}>H1</button><button onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}className={editor.isActive("heading", { level: 2 }) ? "active" : ""}>H2</button><button onClick={() => editor.chain().focus().toggleBulletList().run()}className={editor.isActive("bulletList") ? "active" : ""}>? List</button><button onClick={() => editor.chain().focus().toggleOrderedList().run()}className={editor.isActive("orderedList") ? "active" : ""}>1. List</button><button onClick={() => editor.chain().focus().toggleCodeBlock().run()}className={editor.isActive("codeBlock") ? "active" : ""}>Code</button></div>{/* 編輯區 */}<EditorContent editor={editor} className="editor-content" /></div>)
}export default TiptapEditor

樣式 (editor.css)

.editor {border: 1px solid #ccc;border-radius: 6px;padding: 8px;max-width: 600px;margin: auto;
}.toolbar {border-bottom: 1px solid #ddd;padding-bottom: 6px;margin-bottom: 6px;
}.toolbar button {margin-right: 6px;padding: 4px 8px;border: 1px solid #ccc;background: white;cursor: pointer;border-radius: 4px;
}.toolbar button.active {background: #007bff;color: white;
}.editor-content {min-height: 200px;padding: 6px;outline: none;
}

👉 這樣你就有了:

  • Vue 版 Tiptap + 工具欄
  • React 版 Tiptap + 工具欄
  • TinyMCE 對比版

📌 對比下來:

  • TinyMCE:自帶工具欄,不需要寫 UI。
  • Tiptap:工具欄要自己寫,但能完全定制,甚至做出 Notion 風格。

  • 繼續,為 Tiptap 擴展一個「插入圖片」功能,這樣你能直接對比 TinyMCE 的圖片功能。

    給出 React 示例(Vue 邏輯差不多,換 @tiptap/vue-3 即可)。


  • 補充一個圖片上傳功能

React + Tiptap + 工具欄 + 插入圖片

import React, { useEffect } from "react"
import { EditorContent, useEditor } from "@tiptap/react"
import StarterKit from "@tiptap/starter-kit"
import Image from "@tiptap/extension-image"
import "./editor.css"const TiptapEditor = () => {const editor = useEditor({extensions: [StarterKit,Image, // 啟用圖片擴展],content: "<p>Hello <b>Tiptap</b> with Image 🚀</p>",})useEffect(() => {return () => editor?.destroy()}, [editor])if (!editor) return null// 插入圖片const addImage = () => {const url = window.prompt("請輸入圖片地址")if (url) {editor.chain().focus().setImage({ src: url }).run()}}return (<div className="editor">{/* 工具欄 */}<div className="toolbar"><button onClick={() => editor.chain().focus().toggleBold().run()}className={editor.isActive("bold") ? "active" : ""}>B</button><button onClick={() => editor.chain().focus().toggleItalic().run()}className={editor.isActive("italic") ? "active" : ""}>I</button><button onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}className={editor.isActive("heading", { level: 1 }) ? "active" : ""}>H1</button><button onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}className={editor.isActive("heading", { level: 2 }) ? "active" : ""}>H2</button><button onClick={() => editor.chain().focus().toggleBulletList().run()}className={editor.isActive("bulletList") ? "active" : ""}>? List</button><button onClick={() => editor.chain().focus().toggleOrderedList().run()}className={editor.isActive("orderedList") ? "active" : ""}>1. List</button><button onClick={() => editor.chain().focus().toggleCodeBlock().run()}className={editor.isActive("codeBlock") ? "active" : ""}>Code</button><button onClick={addImage}>🖼 插入圖片</button></div>{/* 編輯區 */}<EditorContent editor={editor} className="editor-content" /></div>)
}export default TiptapEditor

樣式 (editor.css)

.editor {border: 1px solid #ccc;border-radius: 6px;padding: 8px;max-width: 600px;margin: auto;
}.toolbar {border-bottom: 1px solid #ddd;padding-bottom: 6px;margin-bottom: 6px;
}.toolbar button {margin-right: 6px;padding: 4px 8px;border: 1px solid #ccc;background: white;cursor: pointer;border-radius: 4px;
}.toolbar button.active {background: #007bff;color: white;
}.editor-content {min-height: 200px;padding: 6px;outline: none;
}.editor-content img {max-width: 100%;height: auto;border-radius: 4px;margin: 8px 0;
}

👉 效果:

  • 點擊「🖼 插入圖片」會彈出一個輸入框,輸入 URL 就能插圖。
  • 圖片支持縮放、響應式。
  • 如果要擴展成 上傳圖片到服務器再插入,只要改 addImage 方法,走接口拿到 urlsetImage 即可。

👉 總結一句話:

  • 想做 Notion/Google Docs 類現代應用 → 用 Tiptap
  • 想做 CMS/傳統后臺表單 → 用 TinyMCE

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/93482.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/93482.shtml
英文地址,請注明出處:http://en.pswp.cn/web/93482.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

多墨智能-AI一鍵生成工作文檔/流程圖/思維導圖

本文轉載自&#xff1a;多墨智能-AI一鍵生成工作文檔/流程圖/思維導圖 - Hello123工具導航 ** 一、AI 文檔與視覺化創作助手 多墨智能是一款基于人工智能的在線工具&#xff0c;支持一鍵生成專業文檔、流程圖與思維導圖&#xff0c;通過關鍵詞輸入快速完成內容創作&#xff0…

Kafka_Broker_副本基本信息

Kafka副本作用&#xff1a;提高數據可靠性 Kafka默認副本1個&#xff0c;生產環境一般配置為2個&#xff0c;保證數據可靠性&#xff0c;太多副本會增加磁盤存儲空間&#xff0c;增加網絡上數據傳輸&#xff0c;降低效率 Kafka中副本分為&#xff1a;Leader和Follower&#xff…

FreeRTOS 中的守護任務(Daemon Task)

在 FreeRTOS 中&#xff0c;守護任務&#xff08;Daemon Task&#xff09;是一個特殊的系統任務&#xff0c;主要用于管理軟件定時器和其他后臺操作。以下是關于 FreeRTOS 守護任務的詳細信息&#xff1a; 守護任務的作用軟件定時器管理&#xff1a; 當啟用 configUSE_TIMERS 時…

博士招生 | 麻省理工學院 招收化學+人工智能方向 博士/博士后

內容源自“圖靈學術博研社”gongzhonghao學校簡介麻省理工學院&#xff08;MIT&#xff09;QS世界排名第1&#xff0c;是全球科技研究領域的頂尖學府。自成立以來&#xff0c;MIT以其卓越的科研和教育質量贏得了世界的尊敬。學校在科學、工程、經濟和管理等多個領域具有深遠的影…

云計算-OpenStack 實戰運維:從組件配置到故障排查(含 RAID、模板、存儲管理,網絡、存儲、鏡像、容器等)

介紹 在云計算技術快速發展的背景下,OpenStack 作為開源的云計算管理平臺,憑借其靈活性、可擴展性和強大的組件生態,成為構建私有云、公有云和混合云的重要選擇。無論是云主機的創建與管理、存儲方案的配置(如 RAID 陣列、Swift 對象存儲、Cinder 塊存儲),還是網絡編排、…

idea代碼bug檢測插件

代碼檢測工具&#xff08;插件&#xff09;推薦&#xff1a;Alibaba Java Coding Guidelines、CheckStyle、PMD、FindBugs、SonarLint。可以在idea中安裝插件 讓你在關注代碼質量的同時&#xff0c;減少 code review 的工作量&#xff0c;提高 code review 的效率&#xff0c;…

Java String為什么要設計成不可變的?

大家好&#xff0c;我是鋒哥。今天分享關于【Java String為什么要設計成不可變的?】面試題。希望對大家有幫助&#xff1b; Java String為什么要設計成不可變的? 超硬核AI學習資料&#xff0c;現在永久免費了&#xff01; Java中的String類被設計為不可變&#xff08;immut…

集成電路學習:什么是ORB方向性FAST和旋轉BRIEF

ORB:方向性FAST和旋轉BRIEF ORB(Oriented FAST and Rotated BRIEF)是一種在計算機視覺領域廣泛應用的特征描述算法,它結合了FAST角點檢測算法和BRIEF描述子算法的優點,以實現高效且具有旋轉不變性的特征提取和匹配。以下是關于ORB算法的詳細解析: 一、ORB算法概述 …

【langgraph基礎入門】

1. LangGraph圖結構概念說明在以圖構建的框架中&#xff0c;任何可執行的功能都可以作為對話、代理或程序的啟動點。這個啟動點可以是大模型的 API 接口、基于大模型構建的 AI Agent&#xff0c;通過 LangChain 或其他技術建立的線性序列等等&#xff0c;即下圖中的 “Start” …

[逆向知識] AST抽象語法樹:混淆與反混淆的邏輯互換(一)

博客配套代碼發布于github&#xff1a;半自動化cookie更新&#xff08;歡迎順手Star一下?&#xff09; 相關逆向知識&#xff1a; [逆向知識] AST抽象語法樹&#xff1a;混淆與反混淆的邏輯互換&#xff08;二&#xff09;-CSDN博客 相關爬蟲專欄&#xff1a;JS逆向爬蟲實戰…

網絡安全合規6--服務器安全檢測和防御技術

一、服務器安全風險主要威脅&#xff1a;不必要的服務暴露&#xff08;如僅需HTTP卻開放多余端口&#xff09;。外網掃描&#xff08;IP/端口掃描&#xff09;、DDoS攻擊。系統漏洞攻擊&#xff08;操作系統、軟件版本已知漏洞&#xff09;。Web攻擊&#xff08;SQL注入、XSS、…

Mutually aided uncertainty

cycle loss calculation in order to regularize the two aux-decoders 輔助信息 作者未提供代碼

go基礎學習筆記

思維導圖變量 聲明形式為var 變量名 變量類型 賦值形式為變量名變量值 聲明和賦值同時形式為變量名:變量值 多個變量同時聲明使用形式為 var (x intb bool )當有多個變量類型一樣時&#xff0c;可以放在一行&#xff0c;形式為var x,y int,當類型一樣&#xff0c;并且需要賦值同…

C++析構函數和線程退出1

線程作為程序在操作系統中的執行單元&#xff0c;它是活動對象&#xff0c;有生命周期狀態&#xff0c;它是有始有終的。有啟動就有結束&#xff0c;在上篇文章中討論了線程作為數據成員啟動時的順序問題&#xff0c;如何避免構造函數在初始化對象時對線程啟動的負面影響&#…

【語法】JSON格式與基礎語法

文章目錄JSON 簡介JSON 語法規則JSON 名稱/值對JSON 值類型JSON文件存儲JSON示例數據示例Python解析JSON代碼JSON 簡介 JSON 語法是 JavaScript 語法的子集。JSON 是存儲和交換文本信息的語法。JSON: JavaScript Object Notation(JavaScript 對象表示法)。 JSON 語法規則 數…

GitHub 熱榜項目 - 日榜(2025-08-16)

GitHub 熱榜項目 - 日榜(2025-08-16) 生成于&#xff1a;2025-08-16 統計摘要 共發現熱門項目&#xff1a;13 個 榜單類型&#xff1a;日榜 本期熱點趨勢總結 本期GitHub熱榜呈現三大技術熱點&#xff1a;1) AI應用深入垂直領域&#xff0c;SpatialLM將大語言模型應用于空間…

什么是EDA(Exploratory Data Analysis,探索性數據分析)

EDA&#xff08;Exploratory Data Analysis&#xff0c;探索性數據分析&#xff09;是一種在正式建模前&#xff0c;通過統計量和可視化方法來理解數據特征、發現模式與異常、并提出假設的過程。 這張圖里你會看到&#xff1a; 直方圖&#xff1a;展示單變量的分布&#xff0c;…

計算機畢業設計java的小天鵝酒店月子會所管理小天鵝酒店母嬰護理中心管理系統設計小天鵝酒店產后護理會所信息化管理平臺

計算機畢業設計java的小天鵝酒店月子會所管理9zl079&#xff08;配套有源碼 程序 mysql數據庫 論文&#xff09; 本套源碼可以在文本聯xi,先看具體系統功能演示視頻領取&#xff0c;可分享源碼參考。在當今數字化時代&#xff0c;隨著人們對產后護理需求的不斷增加&#xff0c;…

Docker-14.項目部署-DockerCompose

一.DockerCompose大家可以看到&#xff0c;我們部署一個簡單的java項目&#xff0c;其中包含3個容器&#xff1a;MySQLNginxJava項目而稍微復雜的項目&#xff0c;其中還會有各種各樣的其它中間件&#xff0c;需要部署的東西遠不止3個。如果還像之前那樣手動的逐一部署&#xf…

Vue組件基礎解析

一、組件的核心意義 組件是Vue中實現UI復用與邏輯封裝的基礎單元,能將復雜UI拆分為獨立、可重用的部分,最終組織成嵌套的樹狀結構(類似HTML元素嵌套)。Vue組件模型支持自定義內容與邏輯封裝,也能兼容原生Web Component。 二、組件的定義方式 根據是否使用構建步驟,Vue…