文档

MetonaEditor v0.1.3 完整 API、配置与使用指南

安装与引入

# npm 安装
npm install @metona-team/metona-editor

# 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: '',              // 初始 Markdown 文本
  placeholder: '',        // 占位符

  // 视图
  mode: 'split',          // 'edit' | 'split' | 'preview'
  height: 400,            // 数字为 px,字符串原样使用
  toolbar: DEFAULT_TOOLBAR, // 工具栏配置,false 隐藏
  wordCount: true,        // 字数统计状态栏

  // 行为
  autofocus: false,       // 自动聚焦
  spellcheck: false,      // 拼写检查
  readOnly: false,        // 只读模式
  historyLimit: 100,      // 历史栈上限
  historyDebounce: 400,   // 历史防抖延迟(ms)
  syncScroll: true,       // 分屏模式同步滚动
  tabSize: 2,             // 制表符空格数(0 表示 \t)

  // 主题与国际化
  theme: 'auto',          // 'light' | 'dark' | 'auto' | 'warm' | 自定义
  locale: 'zh-CN',        // 'zh-CN' | 'en-US' | 自定义

  // 自定义渲染
  render: null,           // (md, env) => html
  highlight: null,        // (code, lang) => html
  sanitize: null,         // (html) => safeHtml

  // 外观
  className: '',          // 容器额外 class
  style: {},              // 内联样式

  // 插件与回调
  plugins: [],            // 实例级插件数组
  onChange: null,         // (value, editor) => void
  onInput: null,          // (value, editor) => void
  onFocus: null,          // (editor) => void
  onBlur: null,           // (editor) => void
  onSave: null,           // (value, editor) => void
  onModeChange: null,     // (mode, editor) => void
  onFullscreen: null,    // (fullscreen, editor) => void
  onCreate: null,         // (editor) => void
  onDestroy: null,        // (editor) => void
});

工具栏配置

// 默认工具栏(完整按钮)
MeEditor.create(container, { toolbar: true });

// 隐藏工具栏
MeEditor.create(container, { toolbar: false });

// 自定义工具栏 — '|' 为分隔符
MeEditor.create(container, {
  toolbar: ['bold', 'italic', '|', 'h1', 'h2', '|', 'undo', 'redo'],
});

可用动作:

bolditalicstrikethroughunderlinecode h1h2h3quoteulol indentoutdenthr linkimagetable undoredo editsplitpreviewfullscreen

实例 API

内容操作

editor.getValue();                    // 获取 Markdown 文本
editor.setValue(md, { silent });      // 设置内容,silent 不触发 change
editor.getHTML();                     // 获取渲染后的 HTML
editor.refresh();                     // 强制刷新预览(内容未变时)
editor.insert(text, { replace });     // 光标处插入 / 替换选区
editor.wrap(before, after);           // 选区包裹
editor.focus();                       // 聚焦
editor.blur();                        // 失焦

命令执行

editor.exec(action, ...args);         // 执行命令,返回 this 链式调用

editor.exec('bold').exec('h1');        // 链式调用
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引用 >Ctrl+Q
ul/ol无序/有序列表
indent/outdent缩进/反缩进Tab/Shift+Tab
hr水平线 ---
link插入链接 [text](url)Ctrl+K
image插入图片 ![alt](url)
table插入表格
undo/redo撤销/重做Ctrl+Z / Ctrl+Y
edit/split/preview切换模式
fullscreen切换全屏

历史栈

editor.undo();                        // 撤销
editor.redo();                        // 重做
editor.canUndo();                     // 是否可撤销
editor.canRedo();                     // 是否可重做

模式与全屏

editor.setMode('split');              // 设置模式:edit | split | preview
editor.getMode();                     // 获取当前模式
editor.toggleFullscreen();            // 切换全屏
editor.exitFullscreen();              // 退出全屏
editor.isFullscreen();                // 是否全屏

统计与状态

editor.getStats();
// => { characters, words, chineseChars, englishWords, lines, readingTime }

editor.getStatus();
// => { id, mode, theme, locale, fullscreen, readOnly, disabled, destroyed, plugins }

启用/禁用/只读

editor.enable();                      // 启用
editor.disable();                     // 禁用
editor.isDisabled();                  // 是否禁用
editor.setReadOnly(true);             // 只读模式
editor.isReadOnly();                  // 是否只读

事件系统

事件名触发时机回调参数
inputtextarea 原生 input(value, editor)
change内容变化(value, editor)
focus聚焦(editor)
blur失焦(editor)
saveCtrl+S(value, editor)
modeChange模式切换(mode, editor)
fullscreen全屏切换(fullscreen, editor)
destroy销毁()
autosaveautoSave 保存({ key, value })
beforeRender渲染前(editor)
afterRender渲染后(editor)

全局钩子(所有实例共享)

钩子触发时机
beforeCreate构造函数初始化前
afterCreate构造函数初始化完成
beforeRender每次渲染前(全局)
afterRender每次渲染后(全局)
beforeDestroydestroy 前
afterDestroydestroy 后

插件管理

editor.use(plugin, options);          // 安装插件
editor.getPlugins();                  // 获取已安装插件列表
editor.addToolbarButton(config);      // 追加工具栏按钮

生命周期

editor.destroy();                     // 销毁实例
editor.isDestroyed();                 // 是否已销毁

静态 API

import MeEditor from '@metona-team/metona-editor';

// 工厂函数
MeEditor.create(container, options);

// 全局默认插件
MeEditor.use(presetPlugins.autoSave, { delay: 2000 });
MeEditor.use('searchReplace');
MeEditor.use(customPlugin);

// 全局事件钩子
MeEditor.on('beforeCreate', (editor) => {});
MeEditor.off('beforeCreate', handler);

// 主题与语言
MeEditor.setTheme('dark');
MeEditor.setLocale('en-US');

// 状态查询
MeEditor.getStatus(); // => { version, theme, locale, globalPlugins, presetPlugins }

// 销毁全局资源
MeEditor.destroy();

// 内置解析器
import { parseMarkdown, safeUrl, slugify } from '@metona-team/metona-editor';
parseMarkdown('# Hello');           // => '<h1 id="hello">Hello</h1>'
safeUrl('javascript:alert(1)');     // => ''
slugify('Hello World');             // => 'hello-world'

解析器语法参考

语法示例输出
标题# H1 ~ ###### H6<h1> ~ <h6>
段落纯文本<p>
粗体**bold** __bold__<strong>
斜体*italic* _italic_<em>
删除线~~text~~<del>
高亮标记==text==<mark>
上标x^2^<sup>
下标H~2~O<sub>
行内代码`code`<code>
代码块```lang<pre><code>
引用> quote<blockquote>
无序列表- item<ul><li>
有序列表1. item<ol><li>
任务列表- [x] done<li class="me-task-item">
水平线--- *** ___<hr>
表格| a | b |<table>(支持 :---: 列对齐)
链接[text](url)<a>
图片![alt](url)<img>
自动链接<https://...><a>
Emoji:smile: :rocket:😊 🚀(80+ 常用)

XSS 防护

所有文本经 HTML 转义。URL 自动过滤 javascript: vbscript: file: 及非图片 data: 协议。

插件约定

const myPlugin = {
  name: 'myPlugin',
  description: '我的自定义插件',

  install(editor, options) {
    // this 指向插件对象本身
    this._timer = null;
    editor.on('change', this._onChange);
  },

  destroy(editor) {
    if (this._timer) clearTimeout(this._timer);
    editor.off('change', this._onChange);
  },
};

预设插件

autoSave — 自动保存草稿

editor.use(presetPlugins.autoSave, {
  key: 'me-draft-' + editor.id,  // localStorage key
  delay: 1000,                    // 防抖延迟(ms)
});
editor.restoreDraft();             // 恢复草稿
editor.clearDraft();               // 清除草稿
editor.getDraftKey();              // 获取存储 key

exportTool — 导出文件

editor.use(presetPlugins.exportTool);
editor.exportMarkdown('my-doc.md');
editor.exportHTML('my-doc.html', {
  title: '文档标题',
  css: 'body { font-family: sans-serif; }',
  lang: 'zh-CN',
});

searchReplace — 查找替换

editor.use(presetPlugins.searchReplace);
// Ctrl+F → 查找  Ctrl+H → 替换
// Enter → 下一个  Shift+Enter → 上一个  Escape → 关闭

imagePaste — 粘贴图片转 base64

editor.use(presetPlugins.imagePaste);
// 在编辑区 Ctrl+V 粘贴剪贴板图片
// 自动插入 ![](data:image/png;base64,...)

主题系统

// 切换主题
MeEditor.setTheme('light');         // 亮色
MeEditor.setTheme('dark');          // 暗色
MeEditor.setTheme('warm');          // 暖色
MeEditor.setTheme('auto');          // 自动(默认)

// 注册自定义主题
import { themeUtils } from '@metona-team/metona-editor';
themeUtils.registerTheme('ocean', {
  bg: '#001122', text: '#aabbcc', accent: '#00ddff',
});
themeUtils.applyTheme('ocean');

CSS 变量:主题变量限定在 .me-wrapper 元素上,不污染全局样式。支持 @media print 打印样式。

国际化

// 切换语言
MeEditor.setLocale('en-US');
MeEditor.setLocale('zh-CN');

// 翻译函数
import { i18nUtils } from '@metona-team/metona-editor';
i18nUtils.t('bold');                 // => '粗体'(zh-CN)
i18nUtils.t('bold');                 // => 'Bold'(en-US)

// 添加语言
i18nUtils.addTranslations('ja', { bold: '太字', italic: '斜体' });

// 格式化
i18nUtils.formatNumber(1234567);              // => '1,234,567'
i18nUtils.formatCurrency(99.99, 'USD');       // => '$99.99'
i18nUtils.formatDate('2024-01-15');           // => '1/15/2024'