react
如果您想快速体验 Tiptap,您可使用Tiptap Create React App 模板来创建一个新项目。
npx create-react-app my-tiptap-project --template tiptap
如果是从已有的项目中集成进去,以下指南描述了如何将 Tiptap 与您的 React 项目集成。
安装依赖
npm install @tiptap/react @tiptap/pm @tiptap/starter-kit
使用 Tiptap
找到src/App.js
将以下示例代码放入。
import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
const App = () => {
const editor = useEditor({
extensions: [StarterKit],
content: "<p>Hello World!</p>",
});
return (
<div className="App">
<EditorContent editor={editor} />
</div>
);
};
export default App;
启用项目, 您现在应该在浏览器中看到一个漂亮的 Tiptap 示例。
完整的配置
上边的例子 比较简陋,这里给一个设置了基本工具栏 的例子。
🌰 举个例子

- index.js
- style.scss
import './style.scss'
import { EditorContent, useEditor } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import React from 'react';
const MenuBar = ({ editor }) => {
if (!editor) {
return null;
}
return (
<>
<button
onClick={() => editor.chain().focus().toggleBold().run()}
disabled={!editor.can().chain().focus().toggleBold().run()}
className={editor.isActive("bold") ? "is-active" : ""}
>
加粗
</button>
<button
onClick={() => editor.chain().focus().toggleItalic().run()}
disabled={!editor.can().chain().focus().toggleItalic().run()}
className={editor.isActive("italic") ? "is-active" : ""}
>
斜体
</button>
<button
onClick={() => editor.chain().focus().toggleStrike().run()}
disabled={!editor.can().chain().focus().toggleStrike().run()}
className={editor.isActive("strike") ? "is-active" : ""}
>
删除线
</button>
<button
onClick={() => editor.chain().focus().toggleCode().run()}
disabled={!editor.can().chain().focus().toggleCode().run()}
className={editor.isActive("code") ? "is-active" : ""}
>
标记为代码
</button>
<button onClick={() => editor.chain().focus().unsetAllMarks().run()}>
清除格式
</button>
<button onClick={() => editor.chain().focus().clearNodes().run()}>
清除节点
</button>
<button
onClick={() => editor.chain().focus().setParagraph().run()}
className={editor.isActive("paragraph") ? "is-active" : ""}
>
段落
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
className={editor.isActive("heading", { level: 1 }) ? "is-active" : ""}
>
标题1
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={editor.isActive("heading", { level: 2 }) ? "is-active" : ""}
>
标题2
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
className={editor.isActive("heading", { level: 3 }) ? "is-active" : ""}
>
标题3
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
className={editor.isActive("heading", { level: 4 }) ? "is-active" : ""}
>
标题4
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
className={editor.isActive("heading", { level: 5 }) ? "is-active" : ""}
>
标题5
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
className={editor.isActive("heading", { level: 6 }) ? "is-active" : ""}
>
标题6
</button>
<button
onClick={() => editor.chain().focus().toggleBulletList().run()}
className={editor.isActive("bulletList") ? "is-active" : ""}
>
无序列表
</button>
<button
onClick={() => editor.chain().focus().toggleOrderedList().run()}
className={editor.isActive("orderedList") ? "is-active" : ""}
>
有序列表
</button>
<button
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
className={editor.isActive("codeBlock") ? "is-active" : ""}
>
代码块
</button>
<button
onClick={() => editor.chain().focus().toggleBlockquote().run()}
className={editor.isActive("blockquote") ? "is-active" : ""}
>
引用
</button>
<button onClick={() => editor.chain().focus().setHorizontalRule().run()}>
分割线
</button>
<button onClick={() => editor.chain().focus().setHardBreak().run()}>
硬换行
</button>
<button
onClick={() => editor.chain().focus().undo().run()}
disabled={!editor.can().chain().focus().undo().run()}
>
撤销
</button>
<button
onClick={() => editor.chain().focus().redo().run()}
disabled={!editor.can().chain().focus().redo().run()}
>
重做
</button>
</>
);
};
export default () => {
const editor = useEditor({
extensions: [StarterKit],
content: `
<h2>
嗨,
</h2>
<p>
这是一个<strong>tiptap</strong>的<em>基础</em> 示例。 当然 文本编辑器会提供各种文本样式:
</p>
<ul>
<li>
这是一个无序列表,有一个元素 …
</li>
<li>
… 或者两个元素.
</li>
</ul>
<p>
很棒对吧?! 这在里一切皆可编辑, 我们还能提供更多,让我们试试代码块:
</p>
<pre><code class="language-css">body {
display: none;
}</code></pre>
<p>
我知道,我知道,这令人印象深刻。 不过这只是冰山一角!不要忘记检查其他示例,多多的试试看,然后点击一下。
</p>
<blockquote>
哇,太棒了。干得好,孩子! 👏
<br />
— 妈妈
</blockquote>
`,
});
return (
<div>
<MenuBar editor={editor} />
<EditorContent editor={editor} />
</div>
);
};
/* Basic editor styles */
.ProseMirror {
> * + * {
margin-top: 0.75em;
}
ul,
ol {
padding: 0 1rem;
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1.1;
}
code {
background-color: rgba(#616161, 0.1);
color: #616161;
}
pre {
background: #0d0d0d;
color: #fff;
font-family: "JetBrainsMono", monospace;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
code {
color: inherit;
padding: 0;
background: none;
font-size: 0.8rem;
}
}
img {
max-width: 100%;
height: auto;
}
blockquote {
padding-left: 1rem;
border-left: 2px solid rgba(#0d0d0d, 0.1);
}
hr {
border: none;
border-top: 2px solid rgba(#0d0d0d, 0.1);
margin: 2rem 0;
}
}