tiptap扩展开发实战:自定义编辑器功能的完整教程

tiptap扩展开发实战:自定义编辑器功能的完整教程

【免费下载链接】tiptap The headless editor framework for web artisans. 【免费下载链接】tiptap 项目地址: https://gitcode.com/GitHub_Trending/ti/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采用模块化设计,扩展开发需理解三个核心概念:

实战一:创建自定义标记(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,
  ],
})

扩展调试与部署

调试技巧

  1. 使用demos/src/Dev/目录下的开发工具,实时查看文档结构
  2. 通过editor.state.doc.toString()打印文档树结构
  3. 利用packages/core/src/Editor.ts中的onUpdate钩子监听状态变化

打包与发布

扩展开发完成后,通过以下步骤打包:

# 构建扩展
pnpm build:extension highlight

# 本地测试
pnpm link --global packages/extension-highlight

# 发布到npm(需项目维护者操作)
pnpm publish --filter @tiptap/extension-highlight

高级扩展开发资源

官方参考示例

贡献指南

如希望将自定义扩展贡献到官方仓库,需遵循CONTRIBUTING.md规范,主要步骤包括:

  1. 创建扩展文档和测试用例
  2. 添加changeset描述变更内容
  3. 提交PR并通过CI检查

通过本文介绍的方法,你可以构建从简单格式到复杂交互的各类编辑器功能。tiptap的扩展生态系统持续增长,欢迎在官方讨论区分享你的开发经验。

【免费下载链接】tiptap The headless editor framework for web artisans. 【免费下载链接】tiptap 项目地址: https://gitcode.com/GitHub_Trending/ti/tiptap

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

抵扣说明:

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

余额充值