安装与引入
# npm 安装 npm install @metona-team/metona-editor // TypeScript / ES Module import MeEditor from '@metona-team/metona-editor'; const editor = MeEditor.create('#editor', { value: '# Hello World', mode: 'split', }); // 浏览器 UMD <script src="dist/metona-editor.js"></script> <script> const editor = MeEditor.create('#editor'); </script>
全部配置项
所有配置均为可选。
MeEditor.create(container, { // 内容 value: '', placeholder: '', // 视图 mode: 'split', height: 400, toolbar: DEFAULT_TOOLBAR, wordCount: true, lineNumbers: true, outline: false, // 行为 autofocus: false, spellcheck: false, readOnly: false, tabSize: 2, historyLimit: 100, historyDebounce: 400, syncScroll: true, autoBrackets: true, zenMode: false, wordWrap: true, // 主题 / 语言 theme: 'auto', locale: 'zh-CN', // 钩子 render: null, highlight: null, sanitize: null, // 外观 className: '', style: {}, // 插件 / 回调 plugins: [], onChange: null, onInput: null, onFocus: null, onBlur: null, onSave: null, onModeChange: null, onFullscreen: null, onCreate: null, onDestroy: null, onLinkClick: null, });
工具栏
// 默认完整工具栏 MeEditor.create(container, { toolbar: true }); // 隐藏 MeEditor.create(container, { toolbar: false }); // 自定义 | 为分隔符 MeEditor.create(container, { toolbar: ['bold', 'italic', '|', 'undo', 'redo'] });
可用动作:
bolditalicstrikethroughunderlinecode h1h2h3quoteulol indentoutdenthr linkimagetable undoredo editsplitpreviewfullscreen
实例 API
内容操作
editor.getValue(); // => string editor.setValue(md, { silent }); // => this editor.getHTML(); // => string editor.refresh(); // 强制重渲染 editor.insert(text, { replace }); // => this editor.wrap(before, after); // => this editor.focus(); blur();
命令执行
editor.exec(action) // => this, 支持链式
| action | 效果 | 快捷键 |
|---|---|---|
bold | **text** | Ctrl+B |
italic | *text* | Ctrl+I |
strikethrough | ~~text~~ | — |
underline | <u>text</u> | Ctrl+U |
code | `text` | Ctrl+E |
h1/h2/h3 | # / ## / ### | Ctrl+1/2/3 |
quote | > text | Ctrl+Q |
ul/ol | - / 1. 列表 | — |
link | [text](url) | Ctrl+K |
image |  | — |
table | 插入表格 | — |
hr | ---水平线 | — |
indent/outdent | 缩进/反缩进 | Tab / Shift+Tab |
undo/redo | 撤销/重做 | Ctrl+Z / Y |
edit/split/preview | 切换模式 | — |
fullscreen | 全屏 | — |
zen | Zen 模式 | — |
wordwrap | 自动换行 | — |
历史栈
editor.undo(); editor.redo(); editor.canUndo(); editor.canRedo();
模式 / 全屏 / Zen
editor.setMode('split'); editor.getMode(); editor.toggleFullscreen(); isFullscreen(); exitFullscreen(); editor.toggleZen(); isZen(); editor.toggleWordWrap(); setWordWrap(true); isWordWrap();
统计与状态
editor.getStats(); // => { characters, words, chineseChars, englishWords, lines, readingTime } editor.getStatus(); // => { id, mode, theme, locale, fullscreen, readOnly, disabled, destroyed, plugins }
启用 / 禁用 / 只读
editor.enable(); disable(); isDisabled(); editor.setReadOnly(true); isReadOnly();
事件系统
| 事件 | 触发时机 | 参数 |
|---|---|---|
input | textarea 输入 | (value, editor) |
change | 内容变化 | (value, editor) |
focus / blur | 聚焦/失焦 | (editor) |
save | Ctrl+S | (editor) |
modeChange | 模式切换 | (mode, editor) |
fullscreen | 全屏切换 | (fullscreen, editor) |
themeChange | 主题变更 | ({ theme, resolved, config }) |
localeChange | 语言变更 | ({ locale, direction }) |
zenChange | Zen 切换 | (zen, editor) |
destroy | 销毁 | () |
beforeRender / afterRender | 渲染前后 | (editor) |
autosave | autoSave 触发 | ({ key, value }) |
linkClick | 预览链接点击 | ({ href, text }) |
全局钩子
| 钩子 | 触发时机 |
|---|---|
beforeCreate / afterCreate | 实例构造前后 |
beforeRender / afterRender | 全局渲染前后 |
beforeDestroy / afterDestroy | 销毁前后 |
插件管理
editor.use(plugin, options); // 安装 editor.unuse(name); // 卸载 editor.getPlugins(); // 已安装列表 editor.addToolbarButton(config); // 追加按钮
快捷键管理
editor.registerShortcut('Ctrl+Shift+T', handler, 'desc'); editor.unregisterShortcut('Ctrl+Shift+T'); editor.getShortcuts();
生命周期 / Toast
editor.destroy(); isDestroyed(); editor.toast(msg, { type, duration, animation });
静态 API
import MeEditor from '@metona-team/metona-editor'; // 工厂函数 MeEditor.create(container, options); // 全局默认插件 MeEditor.use('autoSave', { delay: 2000 }); MeEditor.use(customPlugin); // 全局钩子 MeEditor.on('beforeCreate', (editor) => {}); MeEditor.off('beforeCreate', handler); // 全局主题 / 语言 MeEditor.setTheme('dark'); MeEditor.setLocale('en-US'); // 解析器独立使用 import { parseMarkdown, parseTokens, renderTokens } from '@metona-team/metona-editor';
解析器语法参考
| 语法 | 示例 | 输出 |
|---|---|---|
| 标题 | # H1 ~ ###### H6 | <h1> ~ <h6> |
| Setext 标题 | H1\n=== | <h1> / <h2> |
| 粗体 | **bold** __bold__ | <strong> |
| 粗斜体 v0.1.15 | ***text*** ___text___ | <em><strong> |
| 斜体 | *italic* _italic_ | <em> |
| 删除线 / 高亮 | ~~del~~ ==mark== | <del> / <mark> |
| 上标 / 下标 | x^2^ H~2~O | <sup> / <sub> |
| 行内代码 | `code` | <code> |
| 代码块 | ```lang | <pre><code> |
| 缩进代码块 | code | <pre><code> |
| 引用 | > quote | <blockquote> |
| 无序列表 | - * + item | <ul><li> |
| 有序列表 | 1. item | <ol><li> |
| 嵌套列表 | 多级缩进 | 多级 <ul>/<ol> |
| 任务列表 | - [x] done | <li class="me-task-item"> |
| 水平线 | --- *** ___ | <hr> |
| 表格 | | a | b | | <table> + 列对齐 |
| 链接 v0.1.15 | [**t**](url) | 文本内支持行内格式 |
| 图片 |  | <img> |
| 自动链接 | <https://...> | <a> |
| 数学公式 | $E=mc^2$ | <span> / <div> |
| 脚注 | text[^1] | <sup> + 底部 |
| 定义列表 | Term\n: def | <dl><dt><dd> |
| Emoji | :smile: :rocket: | 😊 🚀(150+) |
| 反斜杠转义 v0.1.15 | \* \_ | 取消标点特殊含义 |
XSS 防护
所有文本经 escapeHTML 转义,URL 过滤 javascript: / vbscript: / file: / 非图片 data:,提供 sanitize 钩子。
解析器 API
parseTokens / renderTokens
import { parseTokens, renderTokens } from '@metona-team/metona-editor'; const { tokens, footnotes } = parseTokens('# Hello\n\n**world**'); tokens.unshift({ type: 'hr' }); // 渲染前变换 const html = renderTokens(tokens, env, footnotes);
registerBlockHandler
import { registerBlockHandler } from '@metona-team/metona-editor'; registerBlockHandler({ name: 'custom', priority: 8.5, test: (line) => line.match(/^:::/), parse: (lines, i, match) => ({ token: { type: 'alert' }, newIndex: j }) });
插件约定
const myPlugin = { name: 'myPlugin', description: '我的插件', install(editor) { editor.on('change', this._onChange); }, destroy(editor) { editor.off('change', this._onChange); }, };
预设插件
autoSave
editor.use('autoSave', { key: 'draft-key', delay: 1000 }); editor.restoreDraft(); editor.clearDraft();
exportTool
editor.use('exportTool'); editor.exportMarkdown('doc.md'); editor.exportHTML('doc.html');
searchReplace
editor.use('searchReplace'); // Ctrl+F 查找 / Ctrl+H 替换
imagePaste
editor.use('imagePaste'); // 粘贴图片自动转 base64
shortcutHelp
editor.use('shortcutHelp'); // 按 ? 弹出快捷键面板
fileSystem
editor.use('fileSystem'); editor.openFile(); editor.saveFile(); editor.saveFileAs();
主题系统
// 实例级 editor.setTheme('dark'); editor.getTheme(); // 注册自定义 import { themeUtils } from '@metona-team/metona-editor'; themeUtils.registerTheme('ocean', { extends: 'dark', accent: '#00ddff' }); // 外部跟随 editor.getThemeContext().adopt(); // 从父容器继承 // CSS 变量导出 themeUtils.exportCSSVars(); themeUtils.getCSSVariable('accent');
国际化
// 切换 editor.setLocale('en-US'); MeEditor.setLocale('zh-CN'); // 添加翻译 import { i18nUtils } from '@metona-team/metona-editor'; i18nUtils.addTranslations('ja', { bold: '太字' }); // 远程加载 await i18nUtils.loadRemote('/locales/ja.json', 'ja'); // 格式化 i18nUtils.formatNumber(1234567); i18nUtils.formatDate('2024-01-15');