tiptap扩展开发实战:自定义编辑器功能的完整教程
你是否在使用富文本编辑器时遇到功能瓶颈?想给编辑器添加企业专属格式却无从下手?本文将带你从零开始构建tiptap扩展(Extension),通过3个实战案例掌握自定义节点(Node)、标记(Mark)和菜单(Menu)的核心技能,让编辑器完全适配业务需求。
扩展开发准备工作
环境搭建
首先确保本地已安装Node.js(v14+)和pnpm,通过以下命令克隆项目并安装依赖:
git clone https://gitcode.com/GitHub_Trending/ti/tiptap
cd tiptap
pnpm install
项目核心代码位于packages/core/src/目录,扩展开发主要涉及以下文件结构:
| 目录路径 | 作用 |
|---|---|
| packages/core/ | 编辑器核心框架 |
| packages/extension-*/ | 官方扩展示例 |
| demos/src/Examples/ | 使用演示代码 |
核心概念速览
tiptap采用模块化设计,扩展开发需理解三个核心概念:
- 节点(Node):构成文档结构的基础元素,如段落(packages/extension-paragraph/)、标题(packages/extension-heading/)
- 标记(Mark):应用于文本的格式化样式,如粗体(packages/extension-bold/)、链接(packages/extension-link/)
- 扩展(Extension):封装功能的独立模块,通过
Extension类实现(packages/core/src/Extension.ts)
实战一:创建自定义标记(Mark)
以实现"高亮文本"功能为例,创建一个支持背景色设置的标记扩展。
1. 扩展基础结构
在packages/目录下新建extension-highlight/src/index.ts:
import { Mark, markPasteRule } from '@tiptap/core'
export const Highlight = Mark.create({
name: 'highlight',
addOptions() {
return {
HTMLAttributes: {},
color: '#ffff00',
}
},
parseHTML() {
return [{
tag: 'mark',
getAttrs: element => ({
color: (element as HTMLElement).style.backgroundColor,
}),
}]
},
renderHTML({ HTMLAttributes }) {
return ['mark', {
...HTMLAttributes,
style: `background-color: ${this.options.color}`,
}, 0]
},
addCommands() {
return {
setHighlight: attributes => ({ commands }) => {
return commands.setMark(this.name, attributes)
},
toggleHighlight: attributes => ({ commands }) => {
return commands.toggleMark(this.name, attributes)
},
unsetHighlight: () => ({ commands }) => {
return commands.unsetMark(this.name)
},
}
},
addKeyboardShortcuts() {
return {
'Mod-Shift-h': () => this.editor.commands.toggleHighlight(),
}
},
})
export default Highlight
2. 注册与使用
在编辑器初始化时注册扩展:
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
import { Highlight } from './extension-highlight'
new Editor({
element: document.querySelector('#editor'),
extensions: [
StarterKit,
Highlight.configure({
color: '#ffeb3b',
}),
],
content: '<p>选中文本按 <kbd>Ctrl+Shift+H</kbd> 试一下高亮功能</p>',
})
3. 功能测试
运行demo查看效果:
pnpm dev:demos
访问demos/src/Examples/中的测试页面,验证:
- 文本选中时按快捷键添加高亮
- 粘贴带
<mark>标签的HTML内容能否正确解析 - 在demos/src/GuideMarkViews/中查看标记渲染效果
实战二:开发自定义节点(Node)
实现一个"提示框"节点,支持标题和内容区域的自定义组件。
1. 节点定义
创建extension-callout/src/index.ts:
import { Node, mergeAttributes } from '@tiptap/core'
export const Callout = Node.create({
name: 'callout',
group: 'block',
content: 'block+',
defining: true,
addOptions() {
return {
types: ['paragraph'],
HTMLAttributes: {},
icon: 'ℹ️',
}
},
parseHTML() {
return [{
tag: 'div[data-type="callout"]',
}]
},
renderHTML({ HTMLAttributes }) {
return [
'div',
mergeAttributes(
{ 'data-type': 'callout' },
this.options.HTMLAttributes,
HTMLAttributes
),
['div', { class: 'callout-icon' }, this.options.icon],
['div', { class: 'callout-content' }, 0],
]
},
addCommands() {
return {
insertCallout: () => ({ commands }) => {
return commands.insertContent({
type: this.name,
content: [{ type: 'paragraph' }],
})
},
}
},
})
export default Callout
2. 样式与交互
在demos/src/Examples/中添加配套样式:
div[data-type="callout"] {
display: flex;
gap: 0.5rem;
padding: 1rem;
border-radius: 0.5rem;
background: #e3f2fd;
margin: 1rem 0;
}
.callout-icon {
font-size: 1.2rem;
min-width: 1.5rem;
display: flex;
align-items: center;
justify-content: center;
}
实战三:扩展菜单交互
为自定义节点添加上下文菜单,实现快速切换提示框类型的功能。
1. 气泡菜单扩展
创建extension-callout-menu/src/index.ts:
import { BubbleMenu, BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'
import { PluginKey } from '@tiptap/pm/state'
export const CalloutMenu = BubbleMenu.extend({
name: 'calloutMenu',
addOptions() {
return {
...this.parent?.(),
pluginKey: new PluginKey('calloutMenu'),
shouldShow: ({ editor, state, node }) => {
return node.type.name === 'callout'
},
content: () => {
const container = document.createElement('div')
container.innerHTML = `
<select class="callout-select">
<option value="ℹ️">Info</option>
<option value="⚠️">Warning</option>
<option value="❌">Error</option>
</select>
`
container.querySelector('select')?.addEventListener('change', (e) => {
this.editor.commands.updateAttributes('callout', {
icon: (e.target as HTMLSelectElement).value
})
})
return container
},
}
},
})
export default CalloutMenu
2. 集成与使用
在编辑器配置中添加菜单扩展:
import { Callout } from './extension-callout'
import { CalloutMenu } from './extension-callout-menu'
new Editor({
extensions: [
StarterKit,
Callout,
CalloutMenu,
],
})
扩展调试与部署
调试技巧
- 使用demos/src/Dev/目录下的开发工具,实时查看文档结构
- 通过
editor.state.doc.toString()打印文档树结构 - 利用packages/core/src/Editor.ts中的
onUpdate钩子监听状态变化
打包与发布
扩展开发完成后,通过以下步骤打包:
# 构建扩展
pnpm build:extension highlight
# 本地测试
pnpm link --global packages/extension-highlight
# 发布到npm(需项目维护者操作)
pnpm publish --filter @tiptap/extension-highlight
高级扩展开发资源
官方参考示例
- 协作编辑功能:packages/extension-collaboration/
- 表格组件:packages/extension-table/
- 数学公式:packages/extension-mathematics/
贡献指南
如希望将自定义扩展贡献到官方仓库,需遵循CONTRIBUTING.md规范,主要步骤包括:
- 创建扩展文档和测试用例
- 添加changeset描述变更内容
- 提交PR并通过CI检查
通过本文介绍的方法,你可以构建从简单格式到复杂交互的各类编辑器功能。tiptap的扩展生态系统持续增长,欢迎在官方讨论区分享你的开发经验。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



