Tiptap是一個基于ProseMirror的現(xiàn)代化無渲染富文本編輯器框架,其強大的可擴展性允許開發(fā)者創(chuàng)建自定義插件來滿足特定需求。下面我將詳細介紹如何在Tiptap中開發(fā)自定義插件。
## 1. Tiptap插件基礎概念
Tiptap的內容由三大核心組件構成:
- **節(jié)點(Node)**:文檔的基本結構單元,對應DOM節(jié)點
- **標記(Mark)**:用于給選中的文本添加特殊樣式或語義
- **擴展(Extension)**:功能擴展的基礎類,可以擴展編輯器功能
自定義插件通常通過繼承`Extension`類來實現(xiàn)。
## 2. 創(chuàng)建自定義插件的基本步驟
### 2.1 插件基本結構
```javascript
import { Extension } from '@tiptap/core'
const CustomExtension = Extension.create({
name: 'customExtension', // 插件名稱
// 添加配置選項
addOptions() {
return {
// 你的配置項
}
},
// 添加全局屬性
addGlobalAttributes() {
return [
{
types: ['paragraph', 'heading'], // 應用到的節(jié)點類型
attributes: {
// 屬性定義
}
}
]
},
// 添加編輯器命令
addCommands() {
return {
customCommand: () => ({ commands }) => {
// 命令實現(xiàn)
}
}
}
})
```
### 2.2 實際案例:字體大小插件
以下是一個完整的字體大小插件實現(xiàn):
```javascript
import { Extension } from "@tiptap/core";
import "@tiptap/extension-text-style";
// 聲明類型擴展
declare module "@tiptap/core" {
interface Commands<ReturnType> {
fontSize: {
setFontSize: (fontSize: string) => ReturnType;
unsetFontSize: () => ReturnType;
};
}
}
export const FontSizeExtension = Extension.create({
name: "fontSize",
addOptions() {
return {
types: ["textStyle"],
};
},
addGlobalAttributes() {
return [
{
types: this.options.types,
attributes: {
fontSize: {
default: null,
parseHTML: (element) => element.style.fontSize,
renderHTML: (attributes) => {
if (!attributes.fontSize) return {};
return { style: `font-size: ${attributes.fontSize};` };
},
},
},
},
];
},
addCommands() {
return {
setFontSize: (fontSize) => ({ chain }) => {
return chain()
.setMark("textStyle", { fontSize })
.run();
},
unsetFontSize: () => ({ chain }) => {
return chain()
.setMark("textStyle", { fontSize: null })
.removeEmptyTextStyle()
.run();
},
};
},
});
```
### 2.3 行高插件示例
另一個實用的行高插件實現(xiàn):
```javascript
import { Extension } from "@tiptap/core";
declare module "@tiptap/core" {
interface Commands<ReturnType> {
lineHeight: {
setLineHeight: (lineHeight: string) => ReturnType;
unsetLineHeight: () => ReturnType;
};
}
}
export const LineHeightExtension = Extension.create({
name: "lineHeight",
addOptions() {
return {
types: ["paragraph", "heading"],
defaultLineHeight: null,
};
},
addGlobalAttributes() {
return [
{
types: this.options.types,
attributes: {
lineHeight: {
default: this.options.defaultLineHeight,
renderHTML: (attributes) => {
if (!attributes.lineHeight) return {};
return { style: `line-height: ${attributes.lineHeight};` };
},
parseHTML: (element) => ({
lineHeight: element.style.lineHeight || this.options.defaultLineHeight
}),
},
},
},
];
},
addCommands() {
return {
setLineHeight: (lineHeight) => ({ tr, state, dispatch }) => {
tr = tr.setSelection(state.selection);
state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos) => {
if (this.options.types.includes(node.type.name)) {
tr = tr.setNodeMarkup(pos, undefined, {
...node.attrs,
lineHeight,
});
}
});
if (dispatch) dispatch(tr);
return true;
},
unsetLineHeight: () => ({ tr, state, dispatch }) => {
// 類似setLineHeight,但重置行高
}
};
},
});
```
## 3. 插件核心API詳解
### 3.1 addOptions()
用于定義插件的配置選項,這些選項可以通過`this.options`在插件內部訪問。
```javascript
addOptions() {
return {
types: ['paragraph'],
defaultColor: 'red'
}
}
```
### 3.2 addGlobalAttributes()
定義全局屬性,可以應用到指定的節(jié)點類型上。
```javascript
addGlobalAttributes() {
return [{
types: this.options.types,
attributes: {
color: {
default: this.options.defaultColor,
renderHTML: attributes => ({
style: `color: ${attributes.color}`
}),
parseHTML: element => element.style.color
}
}
}]
}
```
### 3.3 addCommands()
添加編輯器命令,可以通過`editor.commands`調用。
```javascript
addCommands() {
return {
setColor: color => ({ chain }) => {
return chain()
.setMark('textStyle', { color })
.run()
},
unsetColor: () => ({ chain }) => {
return chain()
.setMark('textStyle', { color: null })
.removeEmptyTextStyle()
.run()
}
}
}
```
### 3.4 renderHTML()和parseHTML()
控制插件如何渲染到HTML和從HTML解析。
```javascript
// 在addGlobalAttributes或addAttributes中使用
attributes: {
align: {
default: 'left',
renderHTML: attributes => ({
style: `text-align: ${attributes.align}`
}),
parseHTML: element => element.style.textAlign || 'left'
}
}
```
## 4. 插件使用方式
創(chuàng)建插件后,需要在編輯器初始化時注冊:
```javascript
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
import { FontSizeExtension } from './font-size-extension'
const editor = new Editor({
extensions: [
StarterKit,
FontSizeExtension,
// 其他擴展
],
content: '<p>Hello World!</p>',
})
```
## 5. 高級技巧
### 5.1 繼承現(xiàn)有擴展
可以通過`.extend()`方法擴展現(xiàn)有功能:
```javascript
import Heading from "@tiptap/extension-heading";
const CustomHeading = Heading.extend({
addOptions() {
return {
...this.parent?.(), // 保留原有選項
levels: [1, 2, 3], // 修改選項
};
},
});
```
### 5.2 處理節(jié)點選擇
可以使用`addNodeView()`創(chuàng)建復雜的節(jié)點視圖。
### 5.3 使用ProseMirror API
Tiptap基于ProseMirror,可以直接使用ProseMirror的API進行更底層的操作。
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者





暫無評論,快來評論吧!