Tiptap编辑器

主要介绍了编辑器的基础使用,包括依赖安装、基础配置,以及 StarterKit 基础扩展、内嵌图片 Image、编辑状态、拖拽手柄、文本样式扩展包等等

基础介绍

ProseMirror:是一款用于在网页端构建富文本编辑器的工具包,核心目标是弥合 "结构化内容编辑"(如 Markdown、XML)与 "经典所见即所得(WYSIWYG)编辑" 之间的差距 ------ 既让用户能以直观的 WYSIWYG 方式编辑,又能生成干净、语义明确且符合自定义结构的文档,适用于从简单文本编辑到复杂协作系统的各类场景。

Tiptap 是基于 ProseMirror(经行业验证的网页富文本编辑器工具库)构建的无头(Headless)富文本编辑器框架,核心能力是帮助开发者打造 "完全贴合自身及用户需求" 的定制化编辑器。

其底层依赖三大核心机制实现灵活且强大的编辑功能 API:

  1. 事件(Events):监听编辑器状态变化(如内容修改、光标移动);
  2. 命令(Commands):触发编辑操作(如加粗文本、插入列表);
  3. 扩展(Extensions):扩展编辑器功能(如添加表格、AI 辅助创作)。

核心价值是 "按需构建编辑器",既提供基础开源编辑功能,也通过云服务和扩展满足复杂场景需求,核心能力分为五大模块,覆盖从基础编辑到高级协作的全场景:Editor(编辑器)、Collaboration(协作)、Content AI(内容 AI)、Comments(评论)、Documents(文档处理)

安装

  1. @tiptap/react:Tiptap 的 React 绑定包,包含核心功能(如 useEditor 钩子、EditorContent 组件)
  2. @tiptap/pm:Tiptap 依赖的 ProseMirror 底层库,是编辑器运行的核心支撑
  3. @tiptap/starter-kit:基础扩展集合,包含段落、标题、加粗、斜体等常用功能,可快速启动项目
bash 复制代码
pnpm install @tiptap/react @tiptap/pm @tiptap/starter-kit

基础使用

参照官方文档,完成了一个初始 Demo

jsx 复制代码
import { Image } from "antd";
import { styled } from "styled-components";

import { EditorContent, EditorContext, useEditor } from "@tiptap/react";
import { BubbleMenu, FloatingMenu } from "@tiptap/react/menus"; // 导入菜单组件
import StarterKit from "@tiptap/starter-kit"; // 导入基础扩展集合
import { useMemo } from "react";
export default function Page() {
  // 1. 使用 useEditor 钩子初始化编辑器
  const editor = useEditor({
    // 配置扩展(此处使用基础扩展集合)
    extensions: [StarterKit],
    // 编辑器初始内容(HTML 格式)
    content: `
    <h1>第一章原始阶段和商周时期的江南</h1>
    <p>地方特点的青铜器。第一类典型的商代青铜器特别是那些有铭文的铜器,很可能是从中原地区传过来的;第三类具有地方特点的青铜器应是在本地铸造的;第二类青铜器有的可能铸自本地,也有的可能来自中原。</p>
    <p>这些商代铜器除了少数出自遗址和墓葬外,绝大多数出自窖藏,且多出自山顶、山腰、河岸、湖边,很有可能是当时人们祭祀山川、湖泊、日月星辰的遗物。①</p>
    <p>宁乡、湘潭等地出土的商代铜器中,有"己"分裆鼎、"癸母"提梁卤和"戈"卤等少量有铭文的铜器②;在湘潭县青山桥一铜器窖穴中也出土有商末周初的"母"爵,"母"解和"戈"解③。"母"和"戈"本是中原商代铜器中两个常见的族徽,现在江南地区也有铸这两个族徽的铜器出土,说明在商代晚期或末期,他们中的一支曾南迁到了湘中地区。</p>
    <p>湖南境内出土的西周铜器,仍以湘水流域为多,如湘潭、湘乡、浏阳、株洲、望城、衡阳、耒阳、资兴等地都有出土。器形以乐器饶、甬钟和镈为主④,还有湘潭青山桥窖藏出土的爵、解、鼎、凹字形锄等⑤。桃江连河冲出有马簋。⑥</p>
    <p>西周时期的铜饶是紧接着商代晚期的大饶发展而来。商末周初的铜铙为乳钉铙,钲的每面有18个乳钉。这些乳钉的出现可能有两个来源,其乳钉的排列和数量应来源于商代云纹铙上云纹的尾部的上翘,这有江西新干商代大墓中出土的云纹铜饶为证。乳钉的形状应是对于象纹大饶钲边乳钉的承袭。乳钉铙上的乳钉不断升高,在西周初演变为尖锥状和</p>
    `,
  });

  // 缓存 Context 值,避免不必要的重渲染
  const providerValue = useMemo(() => ({ editor }), [editor]);

  return (
    <Container>
      <div className="block-wrap">
        <div className="left">
          <Image src="/pdf/1-1.jpg" />
        </div>
        <div className="right">
          {/* 提供 EditorContext,让子组件可访问编辑器实例 */}
          <EditorContext.Provider value={providerValue}>
            {/* 2. 编辑器内容区域:渲染编辑界面 */}
            <EditorContent editor={editor} />

            {/* 3. 浮动菜单:空行光标定位时显示 */}
            <FloatingMenu editor={editor}>这是浮动菜单</FloatingMenu>

            {/* 4. 气泡菜单:选中文本时显示 */}
            <BubbleMenu editor={editor}>这是气泡菜单</BubbleMenu>
          </EditorContext.Provider>
        </div>
      </div>
    </Container>
  );
}

const Container = styled.div`
  .block-wrap {
    display: flex;
    width: 80%;
    margin: 0 auto;
    > div {
      width: 50%;
    }
  }
`;

显示效果如图 tiptap-1-1 所示:

StarterKit 基础扩展集合

StarterKit 默认包含的核心扩展:文档(Document)、段落(Paragraph)、文本(Text)、标题(Heading)、加粗(Bold)、斜体(Italic)、删除线(Strike)、代码(Code)、无序列表(BulletList)、有序列表(OrderedList)等等。

具体入门套件,可以查看官网:StarterKit

在 StarterKit.configure() 中传入配置对象,通过 "扩展名称" 精准定位需修改的模块

jsx 复制代码
import Strike from "@tiptap/extension-strike"; // 导入删除线扩展

new Editor({
  extensions: [
    StarterKit.configure({
      heading: { levels: [1, 2, 3] }, // 调整标题层级
    }),
  ],
});

内嵌图片 Image

具体可查看官方文档:image

bash 复制代码
# 安装扩展
pnpm install @tiptap/extension-image

使用示例如下所示:

jsx 复制代码
import { Image as TiptapImage } from "@tiptap/extension-image"; // 图片扩展

const editor = useEditor({
  // 配置扩展(此处使用基础扩展集合)
  extensions: [
    StarterKit.configure({
      heading: { levels: [1, 2, 3] }, // 调整标题层级
    }),
    TiptapImage.configure({
      inline: true, // 允许行内
      allowBase64: true, // 允许 base64 格式图片
      HTMLAttributes: {
        class: "tiptap-img-inline", // 自定义样式名
      },
    }),
  ],
  content: `
    <p>宁乡、湘潭等地出土的商代铜器中,有"己<img src="/pdf/1-1-1.png" />"分裆鼎、"癸<img src="https://placehold.co/40x40/6A00F5/white" />"提梁卤和"戈"卤等少量有铭文的铜器②;在湘潭县青山桥一铜器窖穴中也出土有商末周初的"<img src="/pdf/1-1-2.png" />"爵,"<img src="/pdf/1-1-2.png" />"解和"戈"解③。"<img src="/pdf/1-1-2.png" />"和"戈"本是中原商代铜器中两个常见的族徽,现在江南地区也有铸这两个族徽的铜器出土,说明在商代晚期或末期,他们中的一支曾南迁到了湘中地区。</p>
    `,
});

配置了inline: true,设置为行内图片,但是没起作用呀。

排查发现,有个默认样式配置,将图片设置为块元素了,那只能自定义样式处理了呗。

只能添加自定义样式HTMLAttributes: {class:"tiptap-img-inline"}

css 复制代码
.tiptap-img-inline {
  display: inline; /* 强制行内显示 */
}

当然,如果不想要行内显示的话,就不将 img 放到 p 标签内,而是直接放在 p 标签外,这样图片就会块级元素了。

代码展示:

渲染效果展示:

编辑状态控制

jsx 复制代码
// 控制编辑器可编辑状态
const [isEditable, setIsEditable] = useState(false);
useEffect(() => {
  if (editor) {
    editor.setEditable(isEditable);
  }
}, [isEditable, editor]);

// 开关渲染
<Switch
  checkedChildren="开启"
  unCheckedChildren="关闭"
  checked={isEditable}
  onChange={setIsEditable}
/>;

拖拽手柄控制

官方文档:drag-handle-react

文本样式集合包

文本样式集合包含:TextStyle、BackgroundColor(背景色)、Color(颜色)、FontFamily(字体)、FontSize(字号)、LineHeight(行高)

官方文档:text-style-kit

bash 复制代码
# 安装插件
pnpm install @tiptap/extension-text-style
jsx 复制代码
import { TextStyleKit } from "@tiptap/extension-text-style"; // 文本样式扩展

const editor = useEditor({
  extensions: [
    StarterKit,
    // 添加文本样式功能集合,包含字体、颜色、背景色、行高、字体大小等样式控制
    TextStyleKit,
    TiptapImage,
  ],
});
相关推荐
im_AMBER1 小时前
手撕hot100之矩阵!看完这篇就AC~
javascript·数据结构·线性代数·算法·leetcode·矩阵
时光足迹1 小时前
电子书阅读器之笔记高亮(跨段处理)
前端·javascript·react.js
Dabei1 小时前
Android 副屏(Virtual Display)创建与悬浮窗画中画显示实战
前端·架构
Hello-Mr.Wang2 小时前
【保姆级教程】MasterGo MCP + Cursor 一键实现 UI 设计稿还原
前端·javascript·vue.js·ai编程
Dabei2 小时前
Android 无障碍服务实现美团/微信自动化:客户端开发实践
前端·设计模式
华超磊2 小时前
关于手动实现滚动的尝试
前端
宁雨桥2 小时前
前端修行日记之JS 原型与 AI基础常识
前端·javascript·原型模式
程序员陆通2 小时前
月烧 400 刀到不到 20 刀:我是怎么把 OpenClaw 的 Token 账单砍掉 95% 的
java·前端·数据库
水云桐程序员2 小时前
前端教程官方文档|HTML、CSS、JavaScript教程官方文档
前端·javascript·css·html·学习方法