# Mteditor **Repository Path**: meilitao/editor ## Basic Information - **Project Name**: Mteditor - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-10 - **Last Updated**: 2026-10-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # MtEditor > 一套**与框架无关的富文本编辑器** + **跨端富文本渲染器**。MIT 许可,UI 全自研。 MtEditor 由两块**互相解耦**的能力组成: | # | 能力 | 说明 | |---|---|---| | A | **可编辑的富文本内核** | 命令式 API,可被 Vue 3 / Vue 2 / React / Svelte / Layui / 原生 JS 直接集成 | | B | **跨端富文本渲染器** | 同一份 `MtDocument` JSON,在 Web / 小程序 / 鸿蒙上一致地**只读渲染**(不依赖编辑器运行时) | --- ## 特性 - **框架无关**:内核只依赖 Tiptap 3 Core(MIT)与原生 DOM,不绑定任何前端框架;六个框架适配包都是不含编辑逻辑的薄壳。 - **单一真相源**:文档数据模型 `MtDocument`(JSON)是唯一真相源,HTML / Markdown / 纯文本 / 小程序 nodes 全是**派生产物**,同一份数据在编辑、详情页、小程序、导出四处一致。 - **跨端渲染**:Web 端 `renderToString()` 全程不碰 DOM(SSR / 边缘函数可用);小程序端提供 `rich-text` 与递归自定义组件双通道,按文档规模自动切换。 - **UI 完全自研**:工具栏 / 气泡菜单 / 块手柄 / 移动端抽屉 / 目录侧栏均为纯原生 DOM,跨 6 个框架视觉一致,不引入任何 UI 组件库;**不使用 Shadow DOM**,宿主样式可直接覆盖。 - **开箱即用的主题与国际化**:亮 / 暗主题(纯 CSS 变量),内置 `zh-CN` / `en-US`,可注册新语言。 - **移动端三级能力分级**:`full` / `touch` / `readonly` 三档自动降级(不报错),触屏档工具栏吸底 + 抽屉。 - **安全**:AST 白名单 XSS 清洗,**零 DOM 依赖**,Node 与小程序运行时同样生效。 - **可选 AI**:`@mteditor/ai` 为叶子可选包,不装它其余包**一个字节都不多**;provider 由使用者注入,**流式期间不写文档**,确认后才落库(一步撤销)。 - **体积可控**:运行时依赖极少,且不引入 copyleft 许可依赖。实测 gzip:`core` 26.08 KB、`document` 23.58 KB、`theme-default` 3.59 KB、`renderer-mini/wechat` 2.04 KB、`ai` 8.11 KB。 - **浏览器基线**:ES2020,Chrome / Edge ≥ 90、Safari ≥ 14、Firefox ≥ 90、鸿蒙 ArkWeb、Android 9+ WebView。不支持 IE。 --- ## 平台支持 | 平台 | 编辑 | 只读渲染 | 落地方式 | |---|---|---|---| | PC 浏览器 / 移动 H5 | ✅ | ✅ | `@mteditor/core` + `theme-default`,只读用 `renderer-web` | | 鸿蒙 HarmonyOS Next(ArkWeb) | ✅ | ✅ | 同 Web 端(H5 能力完整) | | 微信小程序 | ❌ | ✅ | `@mteditor/renderer-mini/wechat` | | 阿里 / 抖音小程序、uni-app、Taro | ❌ | ⏳ 规划中 | 各端 `rich-text` 白名单需实测,未核实前调用会被拒绝 | | 鸿蒙原生 ArkTS | ❌ | ⏳ 规划中 | `renderer-mini/arkts` | > **小程序端不提供完整富文本编辑**:小程序无稳定 `contenteditable`,业界无可靠原生富文本方案。 > MtEditor 在小程序端提供 **100% 保真的只读渲染**;需要编辑时引导用户跳转 H5 / App 编辑页, > 编辑后回传同一份 `MtDocument`。 --- ## 安装 ```bash npm i @mteditor/core @mteditor/theme-default ``` `@mteditor/core` 已把 `@mteditor/document` 声明为普通依赖,会自动带上; `theme-default` 是纯 CSS,不引它编辑器能跑但没有任何外观。 框架用户改装对应适配包(`core` 会一并带进来): ```bash npm i @mteditor/vue3 # 或 vue2 / react / svelte / layui ``` 只读渲染场景: ```bash npm i @mteditor/renderer-web # Web 详情页 / SSR npm i @mteditor/renderer-mini # 小程序 / uni-app / Taro / 鸿蒙 ArkTS ``` --- ## 快速开始 ### 原生 JS / 任意框架 ```ts import { MtEditor } from '@mteditor/core' import '@mteditor/theme-default/index.css' const editor = new MtEditor({ element: document.getElementById('editor')!, placeholder: '请输入内容…', onChange: ({ json }) => void save(json), // json 是唯一真相源 }) editor.command('toggleBold') editor.command('setHeading', { level: 2 }) editor.getJSON() editor.destroy() ``` 常用 API: | 分类 | API | |---|---| | 内容读写 | `getJSON()` / `setJSON(doc)` / `getHTML()` / `setHTML(html)` / `getText()` / `getMarkdown()` / `setMarkdown(md)` / `insertContent()` | | 编辑操作 | `command(name, payload)`(56 个内置命令)/ `undo()` / `redo()` / `clear()` / `focus()` | | 状态 | `isEmpty()` / `getSelection()` / `getOutline()` / `setReadonly()` / `setTheme()` / `setLocale()` | | 生命周期 | `on(name, handler)` / `destroy()` | ### Vue 3 ```vue ``` ### React ```tsx import { useState } from 'react' import { MtEditor } from '@mteditor/react' import type { MtDocument } from '@mteditor/react' import '@mteditor/theme-default/index.css' export const App = () => { const [doc, setDoc] = useState() return setDoc(json)} options={{ theme: 'light' }} /> } ``` ### Vue 2 ```vue ``` > `v-model` 的 `value`/`input` 与 `modelValue`/`update:modelValue` 两条协议**都收都发**。 ### Svelte 包内只出**版本无关**的纯 TS(`createMtEditor` + `mtEditorStore`,Svelte 4 / 5 通用): ```ts import { onMount } from 'svelte' import { createMtEditor } from '@mteditor/svelte' import '@mteditor/theme-default/index.css' let host: HTMLDivElement onMount(() => { const { editor } = createMtEditor(host, { theme: 'light' }) editor.on('change', ({ json }) => void save(json)) }) ``` ### Layui / ` ``` 也可以直接引全局包(不需要 layui):`var editor = MtEditor.render({ elem: '#editor' })`。 --- ## 只读渲染 ### Web 端 ```ts import { renderToString, renderToDOM } from '@mteditor/renderer-web' import '@mteditor/theme-default/index.css' const { html } = renderToString(doc) // SSR:全程不碰 DOM const { element } = renderToDOM(doc, document.getElementById('view')!) // 详情页:挂载 ``` ### 小程序端 ```ts import { render } from '@mteditor/renderer-mini/wechat' const { mode, nodes, report, autoSwitched } = render(doc, { theme: 'dark' }) // mode 是「实际使用的通道」,宿主必须按它分支;nodes 直接喂给组件 // report 为空表示内容无损;autoSwitched 非 null 表示触发了阈值降级 ``` 接入三步(组件随包分发,小程序无法从 `node_modules` 直读,复制进项目即可): 1. 复制 `node_modules/@mteditor/renderer-mini/components/` 下的 `mt-renderer` / `mt-node` / `mt-theme.wxss` 到项目; 2. 页面 `usingComponents` 声明 `"mt-renderer": "/components/mt/mt-renderer/index"`; 3. WXML 写 ``,样式 `@import` 一次 `mt-theme.wxss`。 > 双通道:`component`(递归自定义组件,默认,样式来自组件 wxss + CSS 变量)与 `richText`(原生 `rich-text`,样式为序列化时内联的字面量);`mode: 'auto'` 按文档节点数自动切换。降级(如 `rich-text` 下的视频 / 音频 / 公式)**始终写入 `report`,不可关闭**。 --- ## AI 能力(可选) ```ts import { MtEditor } from '@mteditor/core' import { createMtAi, createOpenAiCompatProvider } from '@mteditor/ai' const editor = new MtEditor({ element: host }) const ai = createMtAi(editor, { provider: createOpenAiCompatProvider({ baseURL: 'https://api.deepseek.com/v1', // 任何 OpenAI 兼容端点 apiKey: import.meta.env.VITE_AI_KEY, model: 'deepseek-chat', }), }) const result = await ai.run('polish') // 五项动作:续写 / 润色 / 摘要 / 翻译 / 自定义 ai.applyPending('replace') // 结果停在预览里,确认才落库 —— 只占一步撤销 ``` `provider` 只需实现一个 `chat()` 接口,可对接任意模型;不传 `provider` 也可以完全自建 UI (`bubble: false, panel: false` + `ai.subscribe()`)。API key 请放服务端或由宿主注入。 --- ## 包一览 | 包 | 说明 | |---|---| | `@mteditor/core` | 编辑器内核:命令总线(56 命令)、事件、自研 UI、主题与 i18n 接线 | | `@mteditor/document` | 文档模型层:`MtDocument` 的解析 / 序列化 / 清洗 / 校验 / 迁移,**零 DOM 零框架**,Node 与小程序运行时均可用 | | `@mteditor/theme-default` | 纯 CSS 变量主题(亮 / 暗),无 JS | | `@mteditor/renderer-web` | Web 只读渲染器(`renderToString` / `renderToDOM`),不加载编辑器 | | `@mteditor/renderer-mini` | 小程序 / uni-app / Taro / 鸿蒙 ArkTS 只读渲染器,子路径导出(`/wechat` 等) | | `@mteditor/vue3` · `vue2` · `react` · `svelte` · `layui` | 框架适配薄壳;Layui 端额外产出 IIFE 全局包 | | `@mteditor/ai` | 可选 AI 能力包:五项动作 + 多轮对话 | --- ## 各包文档 每个包目录下的 `README.md` 是该包的完整说明(定位 / 安装 / 用法 / props 与事件表 / 常见坑), **随对应的 npm 包一起分发** —— 在 npm 包页面同样可读。 | 包 | 文档 | |---|---| | `@mteditor/core` | [`packages/core/README.md`](./packages/core/README.md) | | `@mteditor/document` | [`packages/document/README.md`](./packages/document/README.md) | | `@mteditor/theme-default` | [`packages/theme-default/README.md`](./packages/theme-default/README.md) | | `@mteditor/renderer-web` | [`packages/renderer-web/README.md`](./packages/renderer-web/README.md) | | `@mteditor/renderer-mini` | [`packages/renderer-mini/README.md`](./packages/renderer-mini/README.md) | | `@mteditor/vue3` · `vue2` · `react` · `svelte` · `layui` | [`packages/adapter-vue3/README.md`](./packages/adapter-vue3/README.md) 等 | | `@mteditor/ai` | [`packages/ai/README.md`](./packages/ai/README.md) | --- ## 许可 [MIT](./LICENSE)。