本文为开发开源项目的真实开发经历,感兴趣的可以来给我的项目点个star,谢谢啦~
具体博文介绍: 开源|Documind协同文档(接入deepseek-r1、支持实时聊天)Documind 🚀 一个支持实时聊天和接入 - 掘金
我干了什么
我定义了两个插件:
font-size
:支持通过setFontSize
设置tiptap
编辑器字体大小,通过unsetFontSize
重置为默认大小。line-height
:支持通过设置setLineHeight
设置tiptap
编辑器行高,通过unsetLineHeight
重置为默认行高。
源码参考
这里就不一点一点讲解了,注释看不懂的话可以叫AI帮你解析。
font-size
插件:
typescript
import { Extension } from "@tiptap/core";
import "@tiptap/extension-text-style";
// 声明类型
declare module "@tiptap/core" {
interface Commands<ReturnType> {
fontSize: {
/** 设置字体大小(支持CSS单位如12px/1.2rem等) */
setFontSize: (fontSize: string) => ReturnType;
/** 清除字体大小设置 */
unsetFontSize: () => ReturnType;
};
}
}
// 创建扩展
export const FontSizeExtension = Extension.create({
name: "fontSize",
// 扩展配置项
addOptions() {
return {
types: ["textStyle"], // 作用对象为文本样式标记
};
},
// 注册全局属性
addGlobalAttributes() {
return [
{
types: this.options.types, // 应用范围(textStyle类型)
attributes: {
fontSize: {
default: null, // 默认无字体大小
// 从DOM解析字体大小(读取style属性)
parseHTML: (element) => element.style.fontSize,
// 渲染到DOM时生成样式
renderHTML: (attributes) => {
if (!attributes.fontSize) {
return {}; // 无设置时返回空对象
}
return {
style: `font-size: ${attributes.fontSize};`, // 生成内联样式
};
},
},
},
},
];
},
// 注册编辑器命令
addCommands() {
return {
/** 设置字体大小命令 */
setFontSize:
(fontSize: string) =>
({ chain }) => {
return chain()
.setMark("textStyle", { fontSize }) // 更新文本样式标记
.run();
},
/** 清除字体大小命令 */
unsetFontSize:
() =>
({ chain }) => {
return chain()
.setMark("textStyle", { fontSize: null }) // 清除字体大小属性
.removeEmptyTextStyle() // 移除空文本样式标记
.run();
},
};
},
});
line-height插件:
typescript
import { Extension } from "@tiptap/core";
// 类型声明:扩展Tiptap的命令接口
declare module "@tiptap/core" {
interface Commands<ReturnType> {
lineHeight: {
/** 设置行高(支持CSS单位如1.5/2/24px等) */
setLineHeight: (lineHeight: string) => ReturnType;
/** 重置为默认行高 */
unsetLineHeight: () => ReturnType;
};
}
}
export const LineHeightExtension = Extension.create({
name: "lineHeight",
// 扩展配置项
addOptions() {
return {
types: ["paragraph", "heading"], // 应用行高样式的节点类型
defaultLineHeight: null, // 默认行高(null表示不设置)
};
},
// 添加全局属性处理
addGlobalAttributes() {
return [
{
types: this.options.types, // 应用到的节点类型
attributes: {
lineHeight: {
// 默认值(从配置项获取)
default: this.options.defaultLineHeight,
// 渲染到HTML时的处理
renderHTML: (attributes) => {
if (!attributes.lineHeight) {
return {};
}
// 将行高转换为行内样式
return {
style: `line-height: ${attributes.lineHeight};`,
};
},
// 从HTML解析时的处理
parseHTML: (element) => {
return {
// 获取行高样式或使用默认值
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 }) => {
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: this.options.defaultLineHeight, // 重置为默认值
});
}
});
if (dispatch) {
dispatch(tr);
}
return true;
},
};
},
});
使用案例
首先我们在extensions中添加扩展以激活
javascript
extensions: [
/*......*/
FontSizeExtension,
LineHeightExtension.configure({
types: ["paragraph", "heading"],
}),
/*......*/
];