纯 JavaScript
你是在没有使用 React 或 Vue 之类前端框架的情况下开发吗?没问题,你可以直接在原生 JavaScript 中使用 Tiptap。
提示
这里的“原生 JavaScript”指的是不使用任何前端框架,但你仍然在使用带有 ES module 导入 的现代 JavaScript(例如通过 Vite、Rollup 或 Webpack)。
如果你想完全跳过构建工具,可以查看下面的 CDN 部分,了解一个可直接在浏览器中运行的配置。
提示
如果你没有使用像 Webpack 或 Rollup 这样的打包工具,请改为按照CDN指南操作。由于 Tiptap 采用模块化构建,你需要在 HTML 中使用 <script type="module"> 来使我们的 CDN 导入生效。
使用构建工具(Vite、Webpack、Rollup)
如果你已经在使用打包工具,或者只是想使用标准的 npm 工作流,推荐采用这种方式。
安装依赖
开始使用时,你需要以下 Tiptap 核心包:
@tiptap/core– 主要的编辑器 API@tiptap/pm– ProseMirror,Tiptap 背后的引擎@tiptap/starter-kit– 常用扩展的便捷集合包
npm install @tiptap/core @tiptap/pm @tiptap/starter-kit添加标记
在你希望挂载编辑器的位置添加以下 HTML:
<div class="element"></div>初始化编辑器
一切准备就绪,现在开始设置编辑器。将以下代码添加到你的 JavaScript 文件中:
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
new Editor({
element: document.querySelector('.element'),
extensions: [StarterKit],
content: '<p>Hello World!</p>',
})在浏览器中打开你的项目,看看 Tiptap 的效果吧。干得漂亮!
不使用构建工具(CDN)
如果你想完全跳过 npm 和构建工具,可以使用 ES module 导入,直接从 CDN 加载 Tiptap。这在所有现代浏览器中都可用。
注意
你的 <script> 标签必须包含 type="module",导入语法才能在浏览器中生效。
最小示例
<script type="module">
import { Editor } from 'https://esm.sh/@tiptap/core'
import StarterKit from 'https://esm.sh/@tiptap/starter-kit'
new Editor({
element: document.querySelector('.element'),
extensions: [StarterKit],
content: '<p>Hello from CDN!</p>',
})
</script>
<div class="element"></div>带工具栏的完整 HTML 文件
下面是一个可直接复制粘贴的示例,其中包含带格式化按钮的工具栏:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tiptap 编辑器</title>
<style>
body {
margin: 2rem;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.editor-container {
max-width: 48rem;
margin: 0 auto;
}
.toolbar {
display: flex;
gap: 0.25rem;
padding: 0.5rem;
border: 1px solid #d1d5db;
border-bottom: none;
border-radius: 0.375rem 0.375rem 0 0;
background: #f9fafb;
flex-wrap: wrap;
}
.toolbar button {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
border: 1px solid transparent;
border-radius: 0.25rem;
background: transparent;
cursor: pointer;
}
.toolbar button:hover {
background: #e5e7eb;
}
.toolbar button.is-active {
background: #111827;
color: #fff;
}
.tiptap {
padding: 0.75rem 1rem;
border: 1px solid #d1d5db;
border-radius: 0 0 0.375rem 0.375rem;
min-height: 10rem;
outline: none;
}
.tiptap p { margin: 0.5rem 0; }
.tiptap h1, .tiptap h2, .tiptap h3 { margin: 1rem 0 0.5rem; }
.tiptap ul, .tiptap ol { padding-left: 1.5rem; }
.tiptap pre {
background: #111827;
color: #f3f4f6;
padding: 0.75rem;
border-radius: 0.25rem;
font-size: 0.875rem;
}
.tiptap code {
background: #f3f4f6;
padding: 0.125rem 0.25rem;
border-radius: 0.25rem;
font-size: 0.875rem;
}
.tiptap pre code {
background: transparent;
padding: 0;
}
</style>
</head>
<body>
<div class="editor-container">
<div class="toolbar" id="toolbar">
<button data-tiptap-button="bold">粗体</button>
<button data-tiptap-button="italic">斜体</button>
<button data-tiptap-button="strike">删除线</button>
<button data-tiptap-button="code">代码</button>
<button data-tiptap-button="h1">H1</button>
<button data-tiptap-button="h2">H2</button>
<button data-tiptap-button="bulletList">无序列表</button>
<button data-tiptap-button="orderedList">有序列表</button>
<button data-tiptap-button="blockquote">引用块</button>
<button data-tiptap-button="codeBlock">代码块</button>
</div>
<div id="editor"></div>
</div>
<script type="module">
import { Editor } from 'https://esm.sh/@tiptap/core'
import StarterKit from 'https://esm.sh/@tiptap/starter-kit'
const editor = new Editor({
element: document.querySelector('#editor'),
extensions: [StarterKit],
content: `
<h1>Welcome to Tiptap</h1>
<p>This is a text editor built with <strong>Vanilla JavaScript</strong> and loaded from a CDN.</p>
<p>Try the toolbar buttons above to format your text.</p>
`,
})
// 绑定工具栏按钮
const buttons = document.querySelectorAll('[data-tiptap-button]')
buttons.forEach((button) => {
button.addEventListener('click', () => {
const command = button.dataset.tiptapButton
switch (command) {
case 'bold':
editor.chain().focus().toggleBold().run()
break
case 'italic':
editor.chain().focus().toggleItalic().run()
break
case 'strike':
editor.chain().focus().toggleStrike().run()
break
case 'code':
editor.chain().focus().toggleCode().run()
break
case 'h1':
editor.chain().focus().toggleHeading({ level: 1 }).run()
break
case 'h2':
editor.chain().focus().toggleHeading({ level: 2 }).run()
break
case 'bulletList':
editor.chain().focus().toggleBulletList().run()
break
case 'orderedList':
editor.chain().focus().toggleOrderedList().run()
break
case 'blockquote':
editor.chain().focus().toggleBlockquote().run()
break
case 'codeBlock':
editor.chain().focus().toggleCodeBlock().run()
break
}
updateActiveButtons()
})
})
function updateActiveButtons() {
const map = {
bold: () => editor.isActive('bold'),
italic: () => editor.isActive('italic'),
strike: () => editor.isActive('strike'),
code: () => editor.isActive('code'),
h1: () => editor.isActive('heading', { level: 1 }),
h2: () => editor.isActive('heading', { level: 2 }),
bulletList: () => editor.isActive('bulletList'),
orderedList: () => editor.isActive('orderedList'),
blockquote: () => editor.isActive('blockquote'),
codeBlock: () => editor.isActive('codeBlock'),
}
buttons.forEach((button) => {
const command = button.dataset.tiptapButton
const check = map[command]
if (check && check()) {
button.classList.add('is-active')
} else {
button.classList.remove('is-active')
}
})
}
editor.on('selectionUpdate', updateActiveButtons)
editor.on('update', updateActiveButtons)
</script>
</body>
</html>将此文件保存为 index.html,然后在任何现代浏览器中打开它即可——无需服务器。
在线演示
你可以在 CodeSandbox 上查看一个类似的可运行示例:
https://codesandbox.io/s/throbbing-smoke-now37q
连接工具栏(原生 JS)
Tiptap 是无头的,因此它不自带内置工具栏。你需要自己连接 UI 按钮。下面是原生 JavaScript 中的实现方式:
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
const editor = new Editor({
element: document.querySelector('#editor'),
extensions: [StarterKit],
content: '<p>Hello World!</p>',
})
// 监听点击并调用 editor 命令
document.querySelector('#bold-button').addEventListener('click', () => {
editor.chain().focus().toggleBold().run()
})
// 检查某个 mark 或节点是否处于激活状态,以便为按钮设置样式
const isBold = editor.isActive('bold')
const isHeading1 = editor.isActive('heading', { level: 1 })
const isBulletList = editor.isActive('bulletList')
// 在选择变化时更新按钮的激活状态
editor.on('selectionUpdate', () => {
document.querySelector('#bold-button').classList.toggle('is-active', editor.isActive('bold'))
})常用编辑器命令
| 命令 | 代码 |
|---|---|
| 粗体 | editor.chain().focus().toggleBold().run() |
| 斜体 | editor.chain().focus().toggleItalic().run() |
| 删除线 | editor.chain().focus().toggleStrike().run() |
| 代码(行内) | editor.chain().focus().toggleCode().run() |
| 标题 1 | editor.chain().focus().toggleHeading({ level: 1 }).run() |
| 标题 2 | editor.chain().focus().toggleHeading({ level: 2 }).run() |
| 无序列表 | editor.chain().focus().toggleBulletList().run() |
| 有序列表 | editor.chain().focus().toggleOrderedList().run() |
| 引用块 | editor.chain().focus().toggleBlockquote().run() |
| 代码块 | editor.chain().focus().toggleCodeBlock().run() |
| 撤销 | editor.chain().focus().undo().run() |
| 重做 | editor.chain().focus().redo().run() |
可用命令请参阅各个扩展的文档。
样式
Tiptap 默认不包含视觉样式——它只输出语义化的 HTML。你可以使用自己的 CSS,或者使用 Tailwind 或 Bootstrap 之类的框架来按你喜欢的方式设置样式。
StarterKit 包含最小化的默认样式,可使文本呈现为一个基础文档的样子。
在 样式指南 中了解更多。