npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mario9/tiptap-editor

v1.0.4

Published

基于 Tiptap + Vue 3 的富文本编辑器组件。

Downloads

111

Readme

@mario9/tiptap-editor

基于 Tiptap + Vue 3 的富文本编辑器组件,支持 Feature Plugin 架构,消费方可按需引入功能模块实现 tree-shaking。

效果预览

编辑器全貌

代码块与表格

数学公式

安装

pnpm add @mario9/tiptap-editor

安装 peer dependencies:

pnpm add vue element-plus katex lowlight @tiptap/core @tiptap/starter-kit @tiptap/vue-3 @tiptap/pm @tiptap/extensions @tiptap/extension-bubble-menu @tiptap/extension-code-block-lowlight @tiptap/extension-highlight @tiptap/extension-horizontal-rule @tiptap/extension-image @tiptap/extension-list @tiptap/extension-mathematics @tiptap/extension-placeholder @tiptap/extension-subscript @tiptap/extension-superscript @tiptap/extension-table @tiptap/extension-text-align @tiptap/extension-typography

快速开始

不传 features 时编辑器只有基础输入能力(无工具栏)。通过 :features 按需组合功能:

<script setup lang="ts">
import { ref } from 'vue'
import {
  TiptapEditor,
  UndoRedoFeature,
  TextStyleFeature,
  TextAlignFeature,
  ListFeature,
  CodeBlockFeature,
  TableFeature,
  MathFeature,
  ImageFeature,
  SeparatorFeature,
} from '@mario9/tiptap-editor'
import '@mario9/tiptap-editor/tiptap-editor.css'

const content = ref('')
</script>

<template>
  <TiptapEditor
    v-model="content"
    :features="[
      UndoRedoFeature,
      TextStyleFeature,
      SeparatorFeature,
      TextAlignFeature,
      ListFeature,
      CodeBlockFeature,
      SeparatorFeature,
      TableFeature,
      MathFeature,
      ImageFeature,
    ]"
  />
</template>

常见场景

最小化配置

只引入用到的 feature,未引入的模块不会进入消费方 bundle:

<TiptapEditor
  v-model="content"
  :features="[UndoRedoFeature, TextStyleFeature]"
/>

最小化配置工具栏

只读模式

<TiptapEditor v-model="content" :readonly="true" />

readonly 时工具栏隐藏,编辑器不可编辑,图片控件仅保留下载,数学公式不可点击编辑。

获取 / 设置内容

v-model 绑定的是 HTML 字符串,直接读写即可:

const content = ref('<p>初始内容</p>')

// 读取当前内容
console.log(content.value)

// 程序化设置内容
content.value = '<h1>新标题</h1><p>新内容</p>'

工具栏顺序

features 数组的顺序即工具栏按钮的顺序,用 SeparatorFeature 插入分隔符:

:features="[
  UndoRedoFeature,     // 撤销重做
  SeparatorFeature,    // ——
  TextStyleFeature,    // 粗体/斜体/下划线/删除线/链接
  TextAlignFeature,    // 对齐
  SeparatorFeature,    // ——
  TableFeature,        // 表格
  ImageFeature,        // 图片
]"

Props

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | modelValue | string | '' | 编辑器内容(HTML 格式),支持 v-model 双向绑定 | | placeholder | string | '请输入内容...' | 编辑器占位符文本 | | upload | (file: File) => Promise<string> | undefined | 图片上传函数,传给 ImageFeature 使用,不传则默认转为 Base64 | | features | FeaturePlugin[] | [] | 功能插件列表,决定工具栏内容和注册的扩展 |

Feature Plugins

| 导出名 | 说明 | 用法 | |--------|------|------| | UndoRedoFeature | 撤销 / 重做 | UndoRedoFeature | | TextStyleFeature | 粗体、斜体、删除线、下划线、链接 | TextStyleFeature | | TextAlignFeature | 文本对齐(左 / 中 / 右 / 两端) | TextAlignFeature | | ListFeature | 有序、无序、任务列表 | ListFeature | | CodeBlockFeature | 代码块(含语法高亮) | CodeBlockFeature | | TableFeature | 表格(含行列增删、移动) | TableFeature | | MathFeature | 数学公式(内联 / 块级,基于 KaTeX) | MathFeature | | ImageFeature | 图片插入(支持自定义上传,默认 Base64) | ImageFeature | | SeparatorFeature | 工具栏分隔符 | SeparatorFeature |

upload 通过 TiptapEditorupload prop 传入,ImageFeature 会自动从 context 中读取:

<TiptapEditor v-model="content" :upload="myUpload" :features="[..., ImageFeature]" />
import { type UploadFn } from '@mario9/tiptap-editor'

const myUpload: UploadFn = async (file) => {
  const formData = new FormData()
  formData.append('file', file)
  const res = await fetch('/api/upload', { method: 'POST', body: formData })
  const data = await res.json()
  return data.url
}

不传 upload 时图片默认转为 Base64。

自定义 Feature Plugin

实现 FeaturePlugin 接口即可创建自定义功能插件。

基础示例

import type { FeaturePlugin } from '@mario9/tiptap-editor'
import MyButton from './MyButton.vue'
import MyExtension from './MyExtension'

export const MyFeature: FeaturePlugin = {
  name: 'my-feature',
  install: () => ({
    extensions: [MyExtension],
  }),
  toolbarComponent: MyButton,
}

含浮层和状态共享的完整示例

如果 feature 需要一个持久渲染的浮层(如对话框),并且工具栏按钮需要触发它,使用 controlComponent + ctx.provide

import { ref, defineComponent, h } from 'vue'
import type { FeaturePlugin } from '@mario9/tiptap-editor'
import MyExtension from './MyExtension'
import MyToolbarButton from './MyToolbarButton.vue'
import MyControlPanel from './MyControlPanel.vue'

export const MyFeature: FeaturePlugin = {
  name: 'my-feature',

  install(ctx) {
    // per-instance 状态(多个编辑器实例互不干扰)
    const isOpen = ref(false)
    const openPanel = () => { isOpen.value = true }

    // 通过 provide 共享给工具栏按钮
    ctx.provide('openMyPanel', openPanel)

    // 闭包组件,捕获 per-instance 状态
    const ControlWrapper = defineComponent({
      setup: () => () => h(MyControlPanel, {
        visible: isOpen.value,
        'onUpdate:visible': (v: boolean) => { isOpen.value = v },
      }),
    })

    return {
      extensions: [MyExtension],
      controlComponent: ControlWrapper,  // 渲染在编辑器内容区之后
    }
  },

  toolbarComponent: MyToolbarButton,
}

工具栏按钮通过 inject 获取共享函数:

// MyToolbarButton.vue
import { inject } from 'vue'

const openMyPanel = inject<() => void>('openMyPanel')

install() 接收 PluginInstallContext(含 readonlyprovideupload),返回 { extensions, controlComponent? }

内置功能(始终启用)

以下功能无需通过 features 配置,始终注册:

  • 标题(H1–H6)
  • 段落、水平线
  • 任务列表(TaskList / TaskItem)
  • 文本对齐扩展(TextAlign)
  • 链接(StarterKit 内置)
  • 气泡菜单(选中文本时浮现)
  • Placeholder

代码高亮

CodeBlockFeature 使用 lowlight 提供语法高亮,默认支持以下常见语言:

Web 开发: JavaScript, TypeScript, HTML, CSS, SCSS, JSON, XML
后端: Python, Java, C, C++, C#, Go, Rust, PHP, Ruby, Swift, Kotlin
脚本/配置: Bash, Shell, YAML, TOML, Makefile, Dockerfile
数据库: SQL
其他: Markdown, Diff, Plaintext

技术栈

  • vue 3.5.25
  • element-plus 2.13.3
  • @tiptap/core 3.22.5

代码结构

src/
├── TiptapEditor.tsx          # 编辑器主组件(feature plugin 驱动)
├── editor.scss               # 工具栏和编辑器样式
├── features/                 # Feature plugin 实现
│   ├── UndoRedoFeature.ts
│   ├── TextStyleFeature.ts
│   ├── TextAlignFeature.ts
│   ├── ListFeature.ts
│   ├── CodeBlockFeature.ts
│   ├── TableFeature.ts
│   ├── MathFeature.ts        # 含对话框状态管理
│   ├── ImageFeature.ts       # 工厂函数,接受 upload 参数
│   └── SeparatorFeature.tsx
├── types/
│   └── plugin.ts             # FeaturePlugin 接口定义
├── components/
│   └── IconButton.tsx        # 基础按钮,包裹 ElButton 和 ElTooltip
├── tiptap-ui/                # 工具栏按钮组件(TSX)
├── tiptap-icons/             # SVG 图标组件(TSX)
└── tiptap-extension/         # 自定义 Tiptap 扩展
    ├── ImageWithAlign.ts     # 带对齐属性的图片扩展
    └── ImageUpload.tsx       # 图片上传节点