┌──────────────────────────────────────────────────────────────┐ │ 📄 shadcn/directory/udecode/plate/(guides)/plugin-methods.cn │ └──────────────────────────────────────────────────────────────┘
╔══════════════════════════════════════════════════════════════════════════════════════════════╗
║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
扩展插件时,默认情况下所有属性都会进行深度合并,但有两个例外:数组会被完全替换,而options对象会进行浅合并。
.configure方法允许你覆盖插件的配置。
const ConfiguredPlugin = MyPlugin.configure({
options: {
myOption: 'new value',
},
});
你也可以使用函数来访问当前配置:
const ConfiguredPlugin = MyPlugin.configure(({ getOptions }) => ({
options: {
...getOptions(),
myOption: `${getOptions().myOption} + extra`,
},
}));
.configurePlugin方法允许你配置嵌套插件的属性:
const TablePlugin = createPlatePlugin({
key: 'table',
plugins: [TableCellPlugin],
}).configurePlugin(TableCellPlugin, {
options: {
cellOption: 'modified',
},
});
.configure类似,修改现有属性但不添加新属性.extend方法允许你扩展插件的配置和功能。
const ExtendedPlugin = MyPlugin.extend({
options: {
newOption: 'new value',
},
});
你也可以使用函数来访问当前配置和编辑器:
const ExtendedPlugin = MyPlugin.extend(({ editor, plugin }) => ({
options: {
newOption: 'new value',
},
handlers: {
onKeyDown: () => {
// 自定义按键逻辑
},
},
}));
.extendPlugin方法允许你扩展嵌套插件的配置和功能:
const TablePlugin = createPlatePlugin({
key: 'table',
plugins: [TableCellPlugin],
}).extendPlugin(TableCellPlugin, {
options: {
newCellOption: 'added',
},
handlers: {
onKeyDown: () => {
// 表格单元格的自定义按键逻辑
},
},
});
虽然这两种方法都可以用于修改插件配置,但存在一些关键差异:
.extend支持链式调用,而.configure不支持.extend返回具有扩展类型的新插件实例,而.configure保持原始类型.extend可以向插件配置添加新属性,而.configure仅修改现有属性根据是否需要扩展插件类型和功能(使用.extend)或仅修改现有配置(使用.configure)来选择适当的方法。
extendSelectors方法允许你向插件添加可订阅的选择器:
const CounterPlugin = createPlatePlugin({
key: 'counter',
options: {
count: 0,
},
}).extendSelectors(({ getOptions }) => ({
doubleCount: () => getOptions().count * 2,
isEven: () => getOptions().count % 2 === 0,
}));
然后你可以在组件或其他插件方法中使用这些选择器:
const CounterComponent = () => {
const count = usePluginOption(CounterPlugin, 'count');
const doubleCount = usePluginOption(CounterPlugin, 'doubleCount');
const isEven = usePluginOption(CounterPlugin, 'isEven');
return (
<div>
<p>Count: {count}</p>
<p>Double Count: {doubleCount}</p>
<p>Is Even: {isEven ? 'Yes' : 'No'}</p>
</div>
);
};
getOption读取值usePluginOption订阅值,当选项变化时重新计算,仅在结果变化时重新渲染。这是与.extendApi的主要区别withComponent方法允许你设置或替换与插件关联的组件。
const ParagraphPlugin = createPlatePlugin({
key: 'p',
node: {
isElement: true,
type: 'p',
},
}).withComponent(ParagraphElement);
插件可以定义自己的API方法和转换方法,这些方法将被合并到编辑器的API和转换中。这是通过extendApi、extendEditorApi、extendTransforms和extendEditorTransforms方法实现的。
使用extendApi添加插件特定的API方法:
const MyPlugin = createPlatePlugin({
key: 'myPlugin',
}).extendApi(() => ({
pluginMethod: () => 'plugin method result',
}));
// 访问插件的API
editor.api.myPlugin.api.pluginMethod();
使用extendEditorApi添加根级API方法:
const MyPlugin = createPlatePlugin({
key: 'myPlugin',
}).extendEditorApi(({ getOptions }) => ({
editorMethod: () => getOptions().someOption,
}));
// 访问插件的API
editor.api.editorMethod();
使用extendTransforms添加插件特定的转换方法:
const MyPlugin = createPlatePlugin({
key: 'myPlugin',
}).extendTransforms(() => ({
pluginTransform: () => {
// 自定义转换逻辑
},
}));
// 访问插件的转换方法
editor.tf.myPlugin.pluginTransform();
// 注意:`editor.tf`是`editor.transforms`的简写
editor.transforms.myPlugin.pluginTransform();
使用extendEditorTransforms添加根级转换方法:
const MyPlugin = createPlatePlugin({
key: 'myPlugin',
}).extendEditorTransforms(({ editor }) => ({
editorTransform: () => {
// 自定义编辑器转换逻辑
},
}));
// 访问插件的转换方法
editor.tf.editorTransform();
overrideEditor方法专门用于在不改变插件类型的情况下覆盖现有的编辑器方法:
const MyPlugin = createPlatePlugin({
key: 'myPlugin',
}).overrideEditor(({ editor, tf: { insertText }, api: { isInline } }) => ({
transforms: {
insertText(text, options) {
// 覆盖insertText行为
insertText(text, options);
},
},
api: {
isInline(element) {
// 覆盖isInline行为
return isInline(element);
},
},
}));
transforms或api对象中的重写方法extendEditorTransforms或extendEditorApi替代)虽然目前Plate中API和转换方法在核心上没有区别,但它们服务于不同的目的,并为未来的可扩展性而设计:
转换方法:
editor.tf.toggleBlock()、editor.tf.toggleMark('bold')API方法:
editor.api.save()、editor.api.debug.log()你可以链式调用这些方法来创建全面的插件:
const MyPlugin = createPlatePlugin({
key: 'myPlugin',
options: {
baseValue: 5,
},
})
.extendApi(() => ({
pluginMethod: () => 'plugin method',
}))
.extendEditorApi(({ getOptions }) => ({
multiply: (factor: number) => getOptions().baseValue * factor,
}))
.extendTransforms(() => ({
pluginTransform: () => {
// 插件特定的转换
},
}))
.extendEditorTransforms(({ editor }) => ({
editorTransform: () => {
// 编辑器特定的转换
},
}));
editor.api.myPlugin.api.pluginMethod();
editor.api.multiply(3);
editor.tf.myPlugin.pluginTransform();
editor.tf.editorTransform();
要将类型化的Slate插件转换为Plate插件,可以使用toPlatePlugin:
const CodeBlockPlugin = toPlatePlugin(createSlatePlugin({ key: 'code_block' }), {
handlers: {},
options: { hotkey: ['mod+opt+8', 'mod+shift+8'] },
});
║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║
╚══════════════════════════════════════════════════════════════════════════════════════════════╝