wang-markdown-render
v1.0.0
Published
Marknote Markdown 渲染与编辑核心 SDK
Readme
wang-markdown-render
Marknote Markdown 编辑器核心 SDK。
使用
最小可用示例:
import { MarkdownCore } from 'wang-markdown-render';
import 'wang-markdown-render/style.css';
const editor = new MarkdownCore(hostElement, {
value: '# 标题',
readOnly: false,
imageBasePath: '',
onChange: (source) => {},
onThemeChange: (theme) => {},
onContextMenu: (payload) => {},
onImageFileAction: async (context) => null,
onImageContextMenu: (payload) => {},
onImageContextMenuClose: (payload) => {},
onImageDblClick: (payload) => {},
pickImagePath: async (context) => '',
});
editor.focus();
editor.execCommand('bold');
editor.findAndReveal('关键字', { direction: 'next', highlight: true, focus: false });
const matches = MarkdownCore.findMarkdownMatches(editor.getValue(), '关键字');
const metrics = MarkdownCore.collectDocumentMetrics(editor.getValue());
const sourceEditor = MarkdownCore.createSourceCodeEditor(sourceHostElement, {
value: editor.getValue(),
onChange: (source) => {},
});只读渲染:
const viewer = new MarkdownCore(hostElement, {
value: markdownSource,
readOnly: true,
});静态工具 API:
const matches = MarkdownCore.findMarkdownMatches(source, 'keyword');
const metrics = MarkdownCore.collectDocumentMetrics(source);
MarkdownCore.applyPageTheme({ cursorColor: '#1890ff' });构造与基础
new MarkdownCore(host, options)
创建编辑器实例并挂载到 host。
options:
value: string初始 Markdown 内容。readOnly: boolean是否只读渲染。为true时保留选择、复制、查找、滚动和程序化setValue,阻止输入、粘贴、剪切、删除、格式化、替换和撤销重做等会修改源码的操作。imageBasePath: string图片相对路径解析基准目录。onChange(source)内容变化回调。onThemeChange(theme)主题变化回调。onContextMenu(payload)文档右键菜单回调。core 只传出上下文,不渲染菜单 UI。onImageFileAction(context)图片右键菜单文件操作回调。onImageContextMenu(payload)图片右键菜单回调。core 只传出图片上下文,不渲染菜单 UI。onImageContextMenuClose(payload)图片菜单上下文被 core 清理时回调,外层可同步关闭菜单。onImageDblClick(payload)图片双击回调,传出当前图片、图片列表和当前索引。onPasteImage(context)粘贴图片保存回调,返回{ success, url, alt }后插入 Markdown 图片。onCodeFormatError(payload)代码块格式化失败回调,传出{ language, reason, message, error }。pickImagePath(context)图片路径选择回调。renderBatchSize: number分批渲染批大小。asyncRenderLineThreshold: number超过该行数后在非聚焦状态下分批渲染。codeBlockLineNumbersVisible: boolean是否显示代码块行号,默认true。
基础实例方法
| API | 说明 |
| --- | --- |
| getValue() | 获取当前 Markdown 源码。 |
| isReadOnly() | 获取当前是否只读。 |
| setReadOnly(readOnly) | 动态切换只读状态。 |
| setValue(nextSource, config = {}) | 设置源码并重新渲染。config.preserveSelection 为 true 时保留选择和行 ID。 |
| getCursorOffset() | 获取当前光标在源码中的偏移位置,无有效位置时返回 null。 |
| getViewportAnchor() | 获取当前视口顶部对应的 Markdown 源码行锚点。 |
| setViewportAnchor(anchor) | 按源码行锚点恢复渲染视图滚动位置。 |
| focus() | 聚焦正文编辑器并恢复选择。 |
| focusAtOffset(offset, options = {}) | 聚焦到指定源码偏移位置。 |
| focusToEnd(options = {}) | 聚焦到文档末尾。 |
| onNextRenderReady(callback) | 在下一次文档渲染就绪后执行一次回调。 |
| blur() | 取消正文编辑器焦点。 |
| destroy() | 销毁编辑器、事件监听、浮层和 DOM。 |
| setTheme(theme) | 设置主题,支持 'light' / 'dark',成功返回 true。 |
| getTheme() | 获取当前主题。 |
| setImageBasePath(imageBasePath, config = {}) | 设置图片基准路径。config.render === false 时不立即重渲染。 |
| setContextMenuHandler(handler) | 设置文档右键菜单回调。 |
| emitChange() | 主动触发 options.onChange。 |
ViewportAnchor 结构:
{
lineIndex: 0,
lineOffsetRatio: 0,
}MarkdownCore.createSourceCodeEditor(host, options)
创建源码模式编辑器实例。
options:
value: string初始 Markdown 源码。onChange(source, update)源码变化回调。
源码编辑器实例方法:
| API | 说明 |
| --- | --- |
| getValue() | 获取当前 Markdown 源码。 |
| setValue(nextSource) | 从外部同步源码到源码编辑器。 |
| focus() | 聚焦源码编辑器。 |
| getViewportAnchor() | 获取当前源码视口锚点。 |
| setViewportAnchor(anchor) | 恢复源码视口滚动位置。 |
| undo() | 撤销源码模式编辑。 |
| redo() | 重做源码模式编辑。 |
| resize() | 重新测量 CodeMirror 布局。 |
| scrollToLine(lineIndex) | 滚动到指定源码行。 |
| selectRange(start, end, lineIndex, options) | 选中源码范围并滚动到可见位置。 |
| destroy() | 销毁源码编辑器实例。 |
命令 API
execCommand(name, options = {})
执行注册命令。返回 true 表示命令存在并已执行。
常用命令:
| 命令 | 说明 |
| --- | --- |
| bold | 加粗。 |
| italic | 斜体。 |
| strike / strikethrough | 删除线。 |
| underline | 下划线,使用 <u>text</u>。 |
| comment | HTML 注释,使用 <!--text-->。 |
| inlineCode | 行内代码。 |
| highlight | 高亮标记 ==text==。 |
| subscript | 下标。 |
| superscript | 上标。 |
| paragraph | 转为普通段落。 |
| heading | 标题,使用 options.level 指定 1-6。 |
| heading1 / heading2 / heading3 | 标题快捷命令。 |
| quote | 引用块。 |
| orderedList | 有序列表。 |
| unorderedList | 无序列表。 |
| taskList | 任务列表。 |
| codeBlock / insertCodeBlock | 代码块。 |
| horizontalRule / insertHorizontalRule | 分割线。 |
| insertLink | 插入链接,options.url 可指定地址。 |
| insertImage | 插入图片,支持 options.url / options.alt。 |
| insertTable | 插入表格,支持 options.rows / options.columns。 |
| insertText | 插入文本,使用 options.text。 |
| undo / redo | 撤销 / 重做。 |
| copy / cut / paste / pasteText / delete | 复制、剪切、粘贴、粘贴纯文本、删除当前选区。 |
| focus | 聚焦编辑器。 |
命令管理
| API | 说明 |
| --- | --- |
| registerCommand(name, handler) | 注册自定义命令。 |
| getCommands() | 获取已注册命令名列表。 |
直接格式化方法
| API | 说明 |
| --- | --- |
| toggleInline(marker) | 按指定 Markdown 标记切换行内样式,如 **、*、`。 |
| toggleHtmlInline(tagName) | 按 HTML 标签切换行内样式,如 u 对应 <u>text</u>。 |
| toggleHtmlComment() | 切换 HTML 注释包裹。 |
| toggleBlock(command) | 切换块样式,如 { type: 'heading', level: 2 }。 |
| toggleTaskLine(lineIndex) | 切换任务列表勾选状态。 |
| copySelection() | 复制当前选中的 Markdown 源码。 |
| cutSelection() | 剪切当前选中的 Markdown 源码。 |
| pasteFromClipboard() | 从系统剪贴板粘贴纯文本。 |
| deleteSelection() | 删除当前选区。 |
| insertTextAtSelection(text) | 替换当前选区为文本。 |
| insertCodeBlock() | 插入代码块。 |
| insertHorizontalRule() | 插入分割线。 |
| insertLink(url = 'https://example.com') | 插入链接。 |
| insertImage(urlOrOptions, options = {}) | 插入图片。 |
| insertTable(options = {}) | 插入表格。 |
查找与替换 API
| API | 说明 |
| --- | --- |
| findMatches(query, options = {}) | 返回全部匹配项,不改变正文状态。 |
| findAndReveal(query, options = {}) | 查找并锚点到下一个/上一个匹配项,默认高亮关键字。 |
| findNextMatch(query, options = {}) | 查找下一个匹配项。 |
| findPreviousMatch(query, options = {}) | 查找上一个匹配项。 |
| selectFindMatch(match, options = {}) | 选中并滚动到指定匹配项。 |
| highlightFindTarget(match, options = {}) | 只高亮匹配关键字。 |
| clearFindTarget() | 清除查找关键字高亮。 |
| replaceFindMatch(match, replacement = '') | 替换指定匹配项。 |
| replaceAllMatches(query, replacement = '', options = {}) | 替换全部匹配项。 |
options:
caseSensitive: boolean区分大小写。wholeWord: boolean全词匹配。direction: 'next' | 'previous'查找方向。highlight: boolean是否高亮查找关键字。focus: boolean是否聚焦正文编辑器。block: ScrollLogicalPosition纵向滚动位置,默认'center'。inline: ScrollLogicalPosition横向滚动位置,默认'nearest'。behavior: ScrollBehavior滚动行为,默认'auto'。pulseDuration: number高亮动效时长。
返回的匹配项结构:
{
id,
index,
start,
end,
text,
lineIndex,
localStart,
localEnd,
endLineIndex,
endLocalOffset,
lineText,
}大纲与滚动 API
| API | 说明 |
| --- | --- |
| getOutline() | 获取文档标题大纲。 |
| getTableOfContentsData() | 等同于 getOutline()。 |
| scrollToLine(lineIndex, options = {}) | 滚动到指定行。 |
| clearOutlineTarget() | 清除侧边栏跳转的整行高亮。 |
scrollToLine 常用 options:
highlight: boolean是否使用侧边栏跳转的整行高亮。select: boolean是否把光标移动到该行开头。block: ScrollLogicalPosition默认'center'。behavior: ScrollBehavior默认'auto'。pulseDuration: number高亮动效时长。
导出与元数据 API
| API | 说明 |
| --- | --- |
| getHTML(options = {}) | 获取渲染后的 HTML。options.wrapper 为 true 时返回外层节点。 |
| exportHTML(options = {}) | 导出完整 HTML 文档字符串。 |
| getMarkdownExportData(options = {}) | 获取 Markdown 导出数据。 |
| getPDFExportData(options = {}) | 获取 PDF 导出数据。 |
| getTitle() | 获取首个标题作为文档标题。 |
| getMetadata() | 获取标题、行数、字数、创建/更新时间等元数据。 |
历史记录 API
| API | 说明 |
| --- | --- |
| undo() | 撤销。 |
| redo() | 重做。 |
| pushHistory(snapshot, options = {}) | 压入历史记录。 |
| restoreHistoryState(state) | 恢复历史状态。 |
表格 API
| API | 说明 |
| --- | --- |
| showTableToolbar(lineIndex, columnIndex = 0) | 显示当前表格工具条。 |
| hideTableToolbar() | 隐藏表格工具条。 |
| updateTableToolbar() | 更新表格工具条状态。 |
| setTableColumnAlignment(alignment) | 设置当前列对齐方式:left / center / right。 |
| resizeCurrentTable(rows, columns) | 调整当前表格行列数。 |
| deleteCurrentTable() | 删除当前表格。 |
| mountTableToolbar() | 挂载表格工具条。 |
| destroyTableToolbar() | 销毁表格工具条。 |
| handleTablePointer(event) | 处理表格区域指针事件。 |
图片 API
| API | 说明 |
| --- | --- |
| insertImage(urlOrOptions, options = {}) | 插入图片。 |
| setImageBasePath(imageBasePath, config = {}) | 设置图片基准路径。 |
| setImagePathPicker(handler) | 设置图片路径选择器。 |
| pickImagePath(context = {}) | 调用图片路径选择器。 |
| queueImagePathFocus(lineIndex, sourceStart) | 等待下一次渲染后聚焦图片路径输入框。 |
| focusPendingImagePathInput() | 聚焦待处理图片路径输入框。 |
| commitImagePathInput(input) | 提交图片路径输入。 |
| openImagePathPicker(input) | 打开图片路径选择器。 |
| handleImagePathKeyDown(event) | 处理图片路径输入快捷键。 |
| handleImagePathPointer(event) | 处理图片路径输入指针事件。 |
| handleImageContextMenu(event) | 生成图片右键上下文并触发 onImageContextMenu。 |
| handleImageDoubleClick(event) | 处理图片双击预览回调。 |
| setImageContextMenuHandler(handler) | 设置图片右键菜单回调。 |
| setImageContextMenuCloseHandler(handler) | 设置图片右键菜单关闭回调。 |
| getImageContextFromEvent(event) | 根据事件目标读取图片上下文。 |
| setImageMenuContext(context) | 缓存当前图片菜单上下文。 |
| getImageMenuContext() | 获取当前图片菜单上下文。 |
| clearImageMenuContext() | 清理当前图片菜单上下文。 |
| hideImageContextMenu() | 清理图片菜单上下文,并触发 onImageContextMenuClose。 |
| destroyImageContextMenu() | 销毁阶段清理图片菜单上下文。 |
| runImageMenuAction(action, context = getImageMenuContext()) | 执行图片菜单动作。 |
onImageDblClick(payload) 回调结构:
{
image: { src, url, filePath, alt, title, kind, lineIndex, sourceStart, sourceEnd, start, end, sourceText },
images: [{ src, url, filePath, alt, title, kind, lineIndex, sourceStart, sourceEnd, start, end, sourceText }],
index: 0,
}onContextMenu(payload) 回调结构:
{
editor,
event,
clientX: 0,
clientY: 0,
position: { x: 0, y: 0 },
readOnly: false,
context: {
block: 'paragraph',
hasSelection: false,
headingLevel: 0,
lineIndex: 0,
source: '',
},
}onImageContextMenu(payload) 回调结构:
{
editor,
event,
context: { src, url, filePath, alt, title, kind, lineIndex, sourceStart, sourceEnd, start, end, sourceText },
image: { src, url, filePath, alt, title, kind, lineIndex, sourceStart, sourceEnd, start, end, sourceText },
clientX: 0,
clientY: 0,
position: { x: 0, y: 0 },
readOnly: false,
}代码块语言 API
| API | 说明 |
| --- | --- |
| showCodeLanguageEditor(block, language = '', syncInput = true) | 显示代码块工具栏并同步语言输入。 |
| hideCodeLanguageEditor() | 隐藏代码块工具栏。 |
| setCodeBlockLanguage(openLineIndex, nextLanguage, selectionSnapshot = null) | 设置代码块语言。 |
| updateCodeLanguageEditor() | 更新代码块工具栏位置与内容。 |
| handleCodeLanguagePointer(event) | 处理代码块语言区域指针事件。 |
| mountCodeLanguageEditor() | 挂载代码块工具栏。 |
| destroyCodeLanguageEditor() | 销毁代码块工具栏。 |
| toggleCodeBlockWrap(force) | 切换代码块自动换行。 |
| setCodeBlockLineNumbersVisible(visible) | 设置是否显示代码块行号。 |
| copyCurrentCodeBlock() | 复制当前代码块内容。 |
渲染与源码同步 API
这些方法通常由 core 内部调用,外部扩展时可按需使用。
| API | 说明 |
| --- | --- |
| renderAll(options = {}) | 全量渲染。 |
| renderAfterChange(previousLines, start, end, insertedText) | 根据变更范围渲染。 |
| renderLinePatch(previousLine, lineIndex) | 单行局部渲染。 |
| replaceLine(lineIndex) | 替换指定行 DOM。 |
| createLineElement(source, lineIndex) | 创建可见行 DOM。 |
| updateActiveLine() | 更新当前活动行和行内 token 状态。 |
| cancelPendingRender() | 取消待处理分批渲染。 |
| commitChange(start, end, text, nextSelection, snapshot) | 提交源码变更。 |
| syncFromDom(historySnapshot = null) | 从 DOM 同步源码。 |
| mount() | 挂载基础 DOM。 |
输入事件 API
这些方法主要供编辑器事件绑定内部使用。
| API | 说明 |
| --- | --- |
| bindEvents() | 绑定编辑器事件。 |
| onBeforeInput(event) | 处理 beforeinput。 |
| onInput(event) | 处理输入同步。 |
| createInputOperation(event) | 根据输入事件生成变更操作。 |
| onKeyDown(event) | 处理键盘事件。 |
| onMouseDown(event) | 处理鼠标按下。 |
| onClick(event) | 处理点击。 |
| onDoubleClick(event) | 处理双击。 |
| onContextMenu(event) | 处理右键菜单。 |
| onPaste(event) | 处理粘贴。 |
| onCopy(event) | 处理复制。 |
| onCut(event) | 处理剪切。 |
| insertTextAtSelection(text) | 在当前选区插入文本。 |
| createSmartLineBreakOperation(snapshot, selection, options = {}) | 创建智能换行操作。 |
| createPrefixDeleteOperation(snapshot) | 创建块前缀删除操作。 |
| createHorizontalRuleDeleteOperation(snapshot, selection, direction) | 创建分割线删除操作。 |
| createTableCellNavigation(snapshot, direction) | 创建表格单元格导航操作。 |
说明:bindEvents() 会在实例上生成 handleBeforeInput、handleInput、handlePaste、handleCopy、handleCut、handleMouseDown、handleClick、handleDoubleClick、handleContextMenu、handleKeyDown、handleFocusIn、handleFocusOut、handleSelectionChange、handleCompositionStart、handleCompositionEnd、handleWindowResize 等事件处理引用,用于解绑和生命周期管理。
静态工具 API
| API | 说明 |
| --- | --- |
| MarkdownCore.appendInlineMarkdown(...args) | 追加行内 Markdown。 |
| MarkdownCore.appendTableMarkdown(...args) | 追加表格 Markdown。 |
| MarkdownCore.buildLineContexts(...args) | 构建行上下文。 |
| MarkdownCore.getBlockPrefixInfo(...args) | 获取块前缀信息。 |
| MarkdownCore.getContinuationInfo(...args) | 获取续行信息。 |
| MarkdownCore.isContextSensitiveLine(...args) | 判断是否为上下文敏感行。 |
| MarkdownCore.isMarkdownSyntaxDisabledContext(...args) | 判断是否禁用 Markdown 语法。 |
| MarkdownCore.parseMarkdownLine(...args) | 解析 Markdown 行。 |
| MarkdownCore.collectDocumentMetrics(...args) | 收集文档指标。 |
| MarkdownCore.findMarkdownMatches(...args) | 查找 Markdown 匹配项。 |
| MarkdownCore.stripHtmlTags(...args) | 剥离 HTML 标签。 |
| MarkdownCore.stripInlineMarkdown(...args) | 剥离行内 Markdown。 |
| MarkdownCore.applyPageTheme(...args) | 应用页面主题。 |
| MarkdownCore.getPageCursorColor(...args) | 获取页面光标颜色。 |
| MarkdownCore.setPageCursorColor(...args) | 设置页面光标颜色。 |
| MarkdownCore.getPageAccentColor(...args) | 获取页面强调色。 |
| MarkdownCore.setPageAccentColor(...args) | 设置页面强调色。 |
| MarkdownCore.createSourceCodeEditor(...args) | 创建源码编辑器。 |
| MarkdownCore.createDocumentMetricsWorker(options = {}) | 创建文档指标 Worker。 |
| MarkdownCore.createFindMatchesWorker(options = {}) | 创建查找匹配 Worker。 |
| MarkdownCore.createLineContextsWorker(options = {}) | 创建行上下文 Worker。 |
静态属性
| 属性 | 说明 |
| --- | --- |
| MarkdownCore.SourceCodeEditorCore | 源码编辑器核心类。 |
| MarkdownCore.MarkdownDocumentMetrics | 文档指标类。 |
| MarkdownCore.MarkdownSearchMatcher | 搜索匹配类。 |
| MarkdownCore.MarkdownLineContextBuilder | 行上下文构建器类。 |
| MarkdownCore.DEFAULT_CURSOR_COLOR | 默认光标颜色。 |
| MarkdownCore.DEFAULT_PAGE_ACCENT_COLOR | 默认页面强调色。 |
| MarkdownCore.TASK_CHECK_PATTERN | 任务勾选正则。 |
| MarkdownCore.patterns | Markdown 正则集合。 |
| MarkdownCore.HEADING_PATTERN | 标题正则。 |
| MarkdownCore.QUOTE_PATTERN | 引用正则。 |
| MarkdownCore.TASK_PATTERN | 任务列表正则。 |
| MarkdownCore.UNORDERED_PATTERN | 无序列表正则。 |
| MarkdownCore.ORDERED_PATTERN | 有序列表正则。 |
| MarkdownCore.FENCE_PATTERN | 代码块正则。 |
| MarkdownCore.FENCE_OPEN_PATTERN | 代码块开始正则。 |
| MarkdownCore.FENCE_CLOSE_PATTERN | 代码块结束正则。 |
| MarkdownCore.HORIZONTAL_RULE_PATTERN | 分割线正则。 |
| MarkdownCore.TABLE_DIVIDER_PATTERN | 表格分隔行正则。 |
| MarkdownCore.TABLE_ROW_PATTERN | 表格行正则。 |
构建
在根项目中构建:
npm run sdk:build在 SDK 目录中单独构建:
npm run build构建产物输出到 dist/。
