插件接口剖析(纯Obsidian接口)
插件接口剖析(纯Obsidian接口)
这里仅展示纯Obsidian接口,Ob中也可使用CodeMirror接口,详见CodeMirror相关笔记
常用
Plugin2(Ex Component)
register…… 方法
注册代码块(registerMarkdownCodeBlockProcessor)
(代码选自 chat-view-qq 插件)
// 注册代码块
this.registerMarkdownCodeBlockProcessor("chat-qq", (source, el, _) => {
new Chat_qq(source, el, _, this).render()
});
注册后处理器(registerMarkdownPostProcessor)
// 注册后处理器
this.registerMarkdownPostProcessor(
buildPostProcessor(() => this.postProcessorConfig) // 好像是每一段(双换行)都会调一次
);
注册编辑器扩展(registerEditorExtension)
(代码选自 cm6-Decoration 插件)
// 注册编辑器扩展
editorExtension: Extension[] = [];
this.registerEditorExtension(this.editorExtension);
this.editorExtension.length = 0; // 清空数组
this.editorExtension.push(suggestionsExtension(this))
const suggestionsExtension = (plugin: MyPlugin): ViewPlugin<PluginValue> => {...}
或
(代码选自 list-callout 插件)
this.registerEditorExtension([
calloutsConfigField.init(() => {
return this.buildEditorConfig();
}),
calloutExtension
]);
注册事件(registerEvent)
创建一个新的文件
import { Plugin } from "obsidian";
export default class ExamplePlugin extends Plugin {
async onload() {
this.registerEvent(this.app.vault.on('create', () => {
console.log('a new file has entered the arena')
}));
}
}
检测打开文件和布局修改
(代码选自 cm6-Decoration 插件)
this.registerEvent(
this.app.workspace.on('file-open', (fileObj) => {
console.log("file-open:", fileObj); // 打开了文件
// 这将保存到插件对象中,并允许CM6扩展查看文件是否刚刚更改,因此即使文档/视口没有更改,它也会运行
if(fileObj) this.onFileOpen = fileObj;
})
);
this.registerEvent(
this.app.workspace.on('layout-change', () => {
// 目前还没有做任何事情,但会监测
console.log("layout-change"); // 布局改变了
})
);
注册Dom事件(registerDomEvent)
(代码选自 cm6-Decoration 插件)
// 如果插件连接了任何全局DOM事件(应用程序中不属于这个插件的部分)
// 当这个插件被禁用时,使用这个函数将自动删除事件监听器。
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
// console.log('click', evt);
});
注册计时事件(registerInterval)
计时事件
如果要以固定延迟重复调用函数,请使用 window.setInterval()
功能与 registerInterval()
方法。
以下示例在状态栏中显示当前时间,每秒更新一次:
import { moment, Plugin } from "obsidian";
export default class ExamplePlugin extends Plugin {
statusBar: HTMLElement;
async onload() {
this.statusBar = this.addStatusBarItem();
this.updateStatusBar();
// highlight-start
this.registerInterval(
window.setInterval(() => this.updateStatusBar(), 1000) // 每秒更新一次
);
// highlight-end
}
updateStatusBar() {
this.statusBar.setText(moment().format("H:mm:ss"));
}
}
其中, Moment 是一个流行的 JavaScript 库,用于处理日期和时间。 Obsidian 内部使用 Moment,因此您无需自行安装。 您可以改为从 Obsidian API 导入它
注册编辑建议(registerEditorSuggest)
(插件 Ad 中使用过)
注册视图窗口(registerView)
略,详见:第三方文档 > 用户界面 > 视图
注册其他
形如 register……
的方法,主要是Plugin2和Component接口声明的
(有五个没见过,其他都见过有插件用)
// Plugin_2 (8)
registerView(type: string, viewCreator: ViewCreator): void; //
registerExtensions(extensions: string[], viewType: string): void; //**
registerEditorExtension(extension: Extension): void; //
registerMarkdownPostProcessor(postProcessor: MarkdownPostProcessor, sortOrder?: number): MarkdownPostProcessor; //
registerMarkdownCodeBlockProcessor(language: string, handler: (source: string, el: HTMLElement, //
ctx: MarkdownPostProcessorContext) => Promise<any> | void, sortOrder?: number): MarkdownPostProcessor;
registerCodeMirror(callback: (cm: CodeMirror.Editor) => any): void; //**
registerObsidianProtocolHandler(action: string, handler: ObsidianProtocolHandler): void; //**
registerEditorSuggest(editorSuggest: EditorSuggest<any>): void; //
// Component (5)
register(cb: () => any): void; //**
registerEvent(eventRef: EventRef): void; //
registerScopeEvent(keyHandler: KeymapEventHandler): void; //**
registerInterval(id: number): number; //
registerDomEvent<K extends keyof WindowEventMap>(el: Window, type: K, callback: //
(this: HTMLElement, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
registerDomEvent<K extends keyof DocumentEventMap>(el: Document, type: K, callback:
(this: HTMLElement, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
registerDomEvent<K extends keyof HTMLElementEventMap>(el: HTMLElement, type: K, callback:
(this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
Plugin_2
export abstract class Plugin_2 extends Component {
/**
* @public
*/
app: App;
/**
* @public
*/
manifest: PluginManifest;
/**
* @public
*/
constructor(app: App, manifest: PluginManifest);
/**
* 将色带图标添加到左侧栏
* @param icon - The icon name to be used. See {@link addIcon}
* @param title - The title to be displayed in the tooltip.
* @param callback - The `click` callback.
* @public
*/
addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => any): HTMLElement;
/**
* @public
*/
addStatusBarItem(): HTMLElement;
/**
* Register a command globally. The command id and name will be automatically prefixed with this plugin's id and name.
* @public
*/
addCommand(command: Command): Command;
/**
* @public
*/
addSettingTab(settingTab: PluginSettingTab): void;
/**
* @public
*/
registerView(type: string, viewCreator: ViewCreator): void;
/**
* 注册 - 视图
* @public
*/
registerExtensions(extensions: string[], viewType: string): void;
/**
* 注册 - 扩展?
* registerExtensions 和 registerEditorExtensions 的区别是什么?
* @public
*/
registerMarkdownPostProcessor(postProcessor: MarkdownPostProcessor, sortOrder?: number): MarkdownPostProcessor;
/**
* 注册 - MD后处理器
* 注册一个特殊的后处理器来处理给定语言和处理程序的隔离代码。
* 这个特殊的后处理器负责删除<pre><代码>,并创建一个<div>
* 将被传递给你的处理程序,并被期望用你的自定义元素填充。
* @示例 list-callouts用了
* @param postProcessor是一个复用接口,本质是(el: HTMLElement, ctx: MarkdownPostProcessorContext): Promise<any> | void;
* @public
*/
registerMarkdownCodeBlockProcessor(language: string, handler: (source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => Promise<any> | void, sortOrder?: number): MarkdownPostProcessor;
/**
* 注册 - 代码块处理器
* 对所有当前加载的CodeMirror实例运行回调,
* 然后为所有未来的CodeMirror实例注册回调。
* @示例 在代码块里渲染的都是
* @public
*/
registerCodeMirror(callback: (cm: CodeMirror.Editor) => any): void;
/**
* 注册 - CodeMirror 6扩展。
* 要为你的插件动态地重新配置cm6扩展,你可以在这里动态地传递一个数组
* 修改它。一旦这个数组被修改,调用' Workspace.updateOptions() '来应用更改
* @param extension - 必须是一个CodeMirror 6 '扩展',或一个数组的扩展
* @public
*/
registerEditorExtension(extension: Extension): void;
/**
* 注册 - 编辑器扩展
* 为 obsidian://url 注册一个处理程序。
* @param action - 操作字符串。例如,“open”对应于“obsidian://open”。
* @param handler - 要触发的回调。您将得到从查询中解码的键-值对。
* 例如:obsidian://open?Key =value 将生成 {"action": "open", " Key ": "value"}
* @示例 list-callouts用了
* @public
*/
registerObsidianProtocolHandler(action: string, handler: ObsidianProtocolHandler): void;
/**
* 注册 - 注册Obsidian协议处理程序
* 注册一个EditorSuggest,它可以在用户输入时提供实时建议
* @public
*/
registerEditorSuggest(editorSuggest: EditorSuggest<any>): void;
/**
* 注册 - 编辑器建议
* @public
*/
loadData(): Promise<any>;
/**
* @public
*/
saveData(data: any): Promise<void>;
}
Component
export class Component {
/**
* Load this component and its children
* @public
*/
load(): void;
/**
* Override this to load your component
* @public
* @virtual
*/
onload(): void;
/**
* Unload this component and its children
* @public
*/
unload(): void;
/**
* Override this to unload your component
* @public
* @virtual
*/
onunload(): void;
/**
* Adds a child component, loading it if this component is loaded
* @public
*/
addChild<T extends Component>(component: T): T;
/**
* 移除子组件,卸载它
* @public
*/
removeChild<T extends Component>(component: T): T;
/**
* 注册一个回调函数,以便在卸载时调用
* @public
*/
register(cb: () => any): void;
/**
* 在卸载时注册一个要分离的事件
* @public
*/
registerEvent(eventRef: EventRef): void;
/**
* 注册事件
* 在卸载时注册一个要分离的DOM事件
* @public
*/
registerDomEvent<K extends keyof WindowEventMap>(el: Window, type: K, callback: (this: HTMLElement, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
/**
* 注册Dom事件
* 在卸载时注册一个要分离的DOM事件
* @public
*/
registerDomEvent<K extends keyof DocumentEventMap>(el: Document, type: K, callback: (this: HTMLElement, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
/**
* 在卸载时注册一个要分离的DOM事件
* @public
*/
registerDomEvent<K extends keyof HTMLElementEventMap>(el: HTMLElement, type: K, callback: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
/**
* 在卸载时注册一个要分离的DOM事件
* @public
*/
registerScopeEvent(keyHandler: KeymapEventHandler): void;
/**
* 注册范围事件
* 注册一个在卸载时取消的间隔(来自setInterval)
* 使用 {@link window.setInterval} 而不是 {@link setInterval},以避免TypeScript混淆NodeJS和浏览器API
* @public
*/
registerInterval(id: number): number;
}
Workspace(Ex Event)
onLayoutReady & updateOptions 方法
例如:
// 【启动高亮】 - 插件加载时
this.app.workspace.onLayoutReady(() => { ////////////////
console.log("onLayoutReady");
this.updateEditorExtension(suggestionsExtension(this));
});
// 启动高亮功能
updateEditorExtension(extension: Extension) {
// 这应该只在启动/加载插件时运行一次
console.log("updateEditorExtension");
this.editorExtension.length = 0;
this.editorExtension.push(extension);
this.app.workspace.updateOptions(); ////////////////
}
Workspace
this.app.workspace
即可获取
export class Workspace extends Events {
/**
* @public
*/
leftSplit: WorkspaceSidedock | WorkspaceMobileDrawer;
/**
* @public
*/
rightSplit: WorkspaceSidedock | WorkspaceMobileDrawer;
/**
* @public
*/
leftRibbon: WorkspaceRibbon;
/**
* @public
*/
rightRibbon: WorkspaceRibbon;
/**
* @public
*/
rootSplit: WorkspaceRoot;
/**
* Indicates the currently focused leaf, if one exists.
*
* Please avoid using `activeLeaf` directly, especially without checking whether
* `activeLeaf` is null.
*
* The recommended alternatives are:
* - If you need information about the current view, use {@link getActiveViewOfType}.
* - If you need to open a new file or navigate a view, use {@link getLeaf}.
*
* @public
* @deprecated - The use of this field is discouraged.
*/
activeLeaf: WorkspaceLeaf | null;
/**
* @public
*/
containerEl: HTMLElement;
/**
* @public
*/
layoutReady: boolean;
/**
* @public
*/
requestSaveLayout: Debouncer<[], Promise<void>>;
/**
* @public
*/
requestSaveHistory: Debouncer<[], void>;
/**
* 如果布局已经准备好,则立即运行回调函数,
* 或将其推到队列中,以便稍后在布局准备就绪时调用。
* @public
* */
onLayoutReady(callback: () => any): void;
/**
* @public
*/
changeLayout(workspace: any): Promise<void>;
/**
* @public
*/
getLayout(): any;
/**
* @public
*/
createLeafInParent(parent: WorkspaceSplit, index: number): WorkspaceLeaf;
/**
* @public
*/
createLeafBySplit(leaf: WorkspaceLeaf, direction?: SplitDirection, before?: boolean): WorkspaceLeaf;
/**
* @public
* @deprecated - You should use {@link getLeaf|getLeaf(true)} instead which does the same thing.
*/
splitActiveLeaf(direction?: SplitDirection): WorkspaceLeaf;
/**
* @public
*/
duplicateLeaf(leaf: WorkspaceLeaf, direction?: SplitDirection): Promise<WorkspaceLeaf>;
/**
* @public
* @deprecated - You should use {@link getLeaf|getLeaf(false)} instead which does the same thing.
*/
getUnpinnedLeaf(type?: string): WorkspaceLeaf;
/**
* Creates a new leaf in a leaf adjacent to the currently active leaf.
* If direction is `'vertical'`, the leaf will appear to the right.
* If direction is `'horizontal'`, the leaf will appear below the current leaf.
*
* @public
*/
getLeaf(newLeaf?: 'split', direction?: SplitDirection): WorkspaceLeaf;
/**
* If newLeaf is false (or not set) then an existing leaf which can be navigated
* is returned, or a new leaf will be created if there was no leaf available.
*
* If newLeaf is `'tab'` or `true` then a new leaf will be created in the preferred
* location within the root split and returned.
*
* If newLeaf is `'split'` then a new leaf will be created adjacent to the currently active leaf.
*
* If newLeaf is `'window'` then a popout window will be created with a new leaf inside.
*
* @public
*/
getLeaf(newLeaf?: PaneType | boolean): WorkspaceLeaf;
/**
* Migrates this leaf to a new popout window.
* Only works on the desktop app.
* @public
*/
moveLeafToPopout(leaf: WorkspaceLeaf, data?: WorkspaceWindowInitData): WorkspaceWindow;
/**
* Open a new popout window with a single new leaf and return that leaf.
* Only works on the desktop app.
* @public
*/
openPopoutLeaf(data?: WorkspaceWindowInitData): WorkspaceLeaf;
/**
* @public
*/
openLinkText(linktext: string, sourcePath: string, newLeaf?: PaneType | boolean, openViewState?: OpenViewState): Promise<void>;
/**
* Sets the active leaf
* @param leaf - The new active leaf
* @param pushHistory - Whether to push the navigation history, or replace the current navigation history.
* @param focus - Whether to ask the leaf to focus.
* @public
*/
setActiveLeaf(leaf: WorkspaceLeaf, pushHistory?: boolean, focus?: boolean): void;
/** 通过id获取树叶
* @public
*/
getLeafById(id: string): WorkspaceLeaf;
/** 获取树叶组
* @public
*/
getGroupLeaves(group: string): WorkspaceLeaf[];
/** 获取最新的树叶
* @public
*/
getMostRecentLeaf(root?: WorkspaceParent): WorkspaceLeaf | null;
/** 获取左树叶
* @public
*/
getLeftLeaf(split: boolean): WorkspaceLeaf;
/** 获取右树叶
* @public
*/
getRightLeaf(split: boolean): WorkspaceLeaf;
/**
* 【重要】例如 const view: View|null = this.app.workspace.getActiveViewOfType(MarkdownView);
* 注意:需要有聚焦(active)才能生效,否则会返回null
* @public
*/
getActiveViewOfType<T extends View>(type: Constructor<T>): T | null;
/**
* Returns the file for the current view if it's a FileView.
*
* Otherwise, it will recent the most recently active file.
* 注意:需要有聚焦(active)才能生效,否则会返回null
* @public
*/
getActiveFile(): TFile | null;
/**
* Iterate through all leaves in the main area of the workspace.
* @public
*/
iterateRootLeaves(callback: (leaf: WorkspaceLeaf) => any): void;
/**
* Iterate through all leaves, including main area leaves, floating leaves, and sidebar leaves.
* @public
*/
iterateAllLeaves(callback: (leaf: WorkspaceLeaf) => any): void;
/**
* 【重要】例如 this.app.workspace.getLeavesOfType(VIEW_TYPE_EXAMPLE).forEach((leaf) => {...})
* @public
*/
getLeavesOfType(viewType: string): WorkspaceLeaf[];
/**
* 根据类型删除树叶节点
* @public
*/
detachLeavesOfType(viewType: string): void;
/**
* 显示树叶节点
* @public
*/
revealLeaf(leaf: WorkspaceLeaf): void;
/**
* @public
*/
getLastOpenFiles(): string[];
/**
* 调用此函数将更新/重新配置所有markdown窗格的选项。
* 它是相当昂贵的,所以不应该经常调用
* @public
*/
updateOptions(): void;
/**
* @public
*/
iterateCodeMirrors(callback: (cm: CodeMirror.Editor) => any): void;
// on()类
/**
* @public
*/
on(name: 'quick-preview', callback: (file: TFile, data: string) => any, ctx?: any): EventRef;
/** 调整大小
* @public
*/
on(name: 'resize', callback: () => any, ctx?: any): EventRef;
/**
* @public
*/
on(name: 'click', callback: (evt: MouseEvent) => any, ctx?: any): EventRef;
/** 叶子节点聚焦切换
* @public
*/
on(name: 'active-leaf-change', callback: (leaf: WorkspaceLeaf | null) => any, ctx?: any): EventRef;
/** 文件打开
* @public
*/
on(name: 'file-open', callback: (file: TFile | null) => any, ctx?: any): EventRef;
/** 布局改变
* @public
*/
on(name: 'layout-change', callback: () => any, ctx?: any): EventRef;
/** 窗口打开
* @public
*/
on(name: 'window-open', callback: (win: WorkspaceWindow, window: Window) => any, ctx?: any): EventRef;
/** 窗口关闭
* @public
*/
on(name: 'window-close', callback: (win: WorkspaceWindow, window: Window) => any, ctx?: any): EventRef;
/** css改变
* Triggered when the CSS of the app has changed.
* @public
*/
on(name: 'css-change', callback: () => any, ctx?: any): EventRef;
/** 文件菜单
* Triggered when the user opens the context menu on a file.
* @public
*/
on(name: 'file-menu', callback: (menu: Menu, file: TAbstractFile, source: string, leaf?: WorkspaceLeaf) => any, ctx?: any): EventRef;
/** 编辑器菜单
* Triggered when the user opens the context menu on an editor.
* @public
*/
on(name: 'editor-menu', callback: (menu: Menu, editor: Editor, view: MarkdownView) => any, ctx?: any): EventRef;
/** 编辑器改变
* Triggered when changes to an editor has been applied, either programmatically or from a user event.
* @public
*/
on(name: 'editor-change', callback: (editor: Editor, markdownView: MarkdownView) => any, ctx?: any): EventRef;
/** 编辑器黏贴
* Triggered when the editor receives a paste event.
* Check for `evt.defaultPrevented` before attempting to handle this event, and return if it has been already handled.
* Use `evt.preventDefault()` to indicate that you've handled the event.
* @public
*/
on(name: 'editor-paste', callback: (evt: ClipboardEvent, editor: Editor, markdownView: MarkdownView) => any, ctx?: any): EventRef;
/**
* Triggered when the editor receives a drop event.
* Check for `evt.defaultPrevented` before attempting to handle this event, and return if it has been already handled.
* Use `evt.preventDefault()` to indicate that you've handled the event.
* @public
*/
on(name: 'editor-drop', callback: (evt: DragEvent, editor: Editor, markdownView: MarkdownView) => any, ctx?: any): EventRef;
/**
* @public
*/
on(name: 'codemirror', callback: (cm: CodeMirror.Editor) => any, ctx?: any): EventRef;
/** 退出
* Triggered when the app is about to quit. Not guaranteed to actually run.
* Perform some best effort cleanup here.
* @public
*/
on(name: 'quit', callback: (tasks: Tasks) => any, ctx?: any): EventRef;
}
Event
export class Events {
/**
* @public
*/
on(name: string, callback: (...data: any) => any, ctx?: any): EventRef;
/**
* @public
*/
off(name: string, callback: (...data: any) => any): void;
/**
* @public
*/
offref(ref: EventRef): void;
/**
* @public
*/
trigger(name: string, ...data: any[]): void;
/**
* @public
*/
tryTrigger(evt: EventRef, args: any[]): void;
}
其他
Comand
/**
* @public
*/
export interface Command {
/**
* 用于标识该命令的全局唯一ID。
* @public
*/
id: string;
/**
* Human friendly name for searching.
* @public
*/
name: string;
/**
* Icon ID to be used in the toolbar.
* @public
*/
icon?: string;
/** @public */
mobileOnly?: boolean;
/**
* Whether holding the hotkey should repeatedly trigger this command. Defaults to false.
* @public
*/
repeatable?: boolean;
/**
* 简单的回调,全局触发。
* @public
*/
callback?: () => any;
/**
* 复杂回调,覆盖简单回调。用于“检查”当前环境下命令是否可以执行。
* 例如,如果您的命令要求活动聚焦窗格是MarkdownSourceView,那么只有在条件满足时才应该返回true。
* 返回false或undefined将导致命令从命令面板中隐藏。
*
* @param checking - 命令面板是否只是检查,您的命令是否应该立即执行。
* 如果checking为true,则该函数不应执行任何操作。
* 如果checking为false,则该函数应执行该操作。
*
* @returns 当前是否可以执行该命令。
* @public
*/
checkCallback?: (checking: boolean) => boolean | void;
/**
* 只在用户处于编辑器中时触发的命令回调。
* 覆盖 `callback` and `checkCallback`
* @public
*/
editorCallback?: (editor: Editor, view: MarkdownView) => any;
/**
* 只在用户处于编辑器中时触发的命令回调。
* 覆盖 `editorCallback`, `callback` and `checkCallback`
* @public
*/
editorCheckCallback?: (checking: boolean, editor: Editor, view: MarkdownView) => boolean | void;
/**
* 设置默认热键。建议插件尽可能避免设置默认热键,
* 避免热键与用户设置的热键冲突,即使自定义热键具有更高的优先级。
* @public
*/
hotkeys?: Hotkey[];
}
Markdown相关
MarkdownRenderer(Ex MarkdownRenderChild, Ex Component)
MarkdownRenderer
export abstract class MarkdownRenderer extends MarkdownRenderChild implements MarkdownPreviewEvents, HoverParent, MarkdownFileInfo {
// 可以将字符串生成为Markdown渲染结果(HTML),注意是最终渲染的结果
static renderMarkdown(markdown: string, el: HTMLElement, sourcePath: string, component: Component): Promise<void>;
}
MarkdownRenderChild
export class MarkdownRenderChild extends Component {
/** @public */
containerEl: HTMLElement;
/**
* @param containerEl - This HTMLElement will be used to test whether this component is still alive.
* It should be a child of the markdown preview sections, and when it's no longer attached
* (for example, when it is replaced with a new version because the user edited the markdown source code),
* this component will be unloaded.
* @public
*/
constructor(containerEl: HTMLElement);
}
MarkdownView
MarkdownPostProcessorContext(ctx)
定义,内容不多,主要使用 addChild
方法
export interface MarkdownPostProcessorContext {
/**
* @public
*/
docId: string;
/** @public */
sourcePath: string;
/** @public */
frontmatter: any | null | undefined;
/**
* 添加将由呈现器管理其生命周期的子组件。
* 使用此命令向渲染器添加一个依赖的子组件,这样如果子组件的containerEl被移除,组件的unload将被调用。
* @public
*/
addChild(child: MarkdownRenderChild): void;
/**
* 获取此元素在此时间点的节信息。
* 只在需要此信息之前调用此函数以获得最新版本。
* 此函数在许多情况下也可能返回null;如果使用它,必须准备好处理空值
* @public
*/
getSectionInfo(el: HTMLElement): MarkdownSectionInformation | null;
}
使用场景,这两个方法都会传入该实例
this.registerMarkdownCodeBlockProcessor("tx", this.renderMarkdown);
this.registerMarkdownPostProcessor(this.processTextSection);
export function renderMarkdown(
src: string, // 代码块内容
el: HTMLElement, // 代码块渲染的元素
ctx: MarkdownPostProcessorContext // md后处理器
) {}
export function processTextSection(
el: HTMLElement, // 代码块渲染的元素
ctx: MarkdownPostProcessorContext // md后处理器
) {}
一般使用方法
let child = new MarkdownRenderChild(blockEl);
ctx.addChild(child);
MarkdownRenderer.renderMarkdown(src, blockEl, ctx.sourcePath, child);
const src = getSourceMarkdown(el, ctx);
使用举例
(代码片段为Obsidian第三方手册的后处理器的emoji替换示例)
for (let index = 0; index < codeblocks.length; index++) {
const codeblock = codeblocks.item(index);
const text = codeblock.innerText.trim();
if (text[0] === ":" && text[text.length - 1] === ":") {
// highlight-next-line
ctx.addChild(new Emoji(codeblock, text));
}
}
调试输出ctx
{
addChild: f(e)
containerEl: div.markdown-preview-sizer.markdown-preview-section // 显示整篇文章的div
docId
el: div // 所在段落的div(严格换行的一行,非严格换行的一段)
fromtmatter
getSectionInfo
promises
sourcePath // 这篇文档在Vault中的路径
}
链接到当前文件 0
没有文件链接到当前文件