百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

任由文字肆意流淌,更自由的开源 Markdown 编辑器

myzbx 2025-06-10 16:53 7 浏览

对于创作平台来说内容编辑器是十分重要的功能,强大的编辑器可以让创作者专注于创作“笔”下生花。而最好取悦程序员创作者的方法之一就是支持 Markdown 写作,因为大多数程序员都是用 Markdown 来写文章。

Markdown 作为程序员写作的心头爱,有很多优点:

  • 通过语法实现排版,不需要点选手动设置样式
  • 快速实现复杂内容,如:代码块、超链接、公式等
  • 让创作者有更多时间专注于内容

但,同样的也有些缺点:

  • 有一定的学习门槛,对于非程序员不太友好
  • 看原文档就像看“代码”,预览效果需要工具或编辑器支持

那有没有能够即保留 Markdown 带来的便利,同时又降低门槛的办法呢?大多数老玩家会脱口而出:Typora

Typora 直接使用完全没有问题,但由于它没有开源。如果想在自己的项目实现类似的 Markdown 编辑器,就需要另寻方案了。

如果你正在寻找功能强大、易于接入、所见即所得的 Markdown 编辑器、组件、插件,就请花 5 分钟读完本文!

接下来 HelloGitHub 带来的开源项目完全满足上述需求。Milkdown 一款高颜值+自由(插件)的所见即所得,集合 Markdown 编辑器、组件、插件于一身的开源项目。

https://github.com/Saul-Mirone/milkdown

你想要的功能它都有,不要的功能也可以通过删减插件,减少体积。插件的设计思想+完善的中文文档,让你分分钟定制出最适合自己的 Markdown 编辑器!

下面跟着项目作者一起来感受 Milkdown 的魅力吧。

一、上手

下面提供了 2 种方式,可直接体验:

在线尝试:https://milkdown.dev/#/online-demo

VS Code 插件:https://marketplace.visualstudio.com/items?itemName=mirone.milkdown

1.1 功能展示

方便的编写表格:

直接粘贴和复制 Markdown 文本:

甚至协同编辑:

双栏 Markdown 编辑器很常见。但 双向绑定 的 Markdown 编辑器,目前仅此一家:

功能方面就介绍这么多,下面用 Milkdown 轻松实现个编辑器。

1.2 第一个编辑器

Milkdown 的核心以及各种插件都是独立的 NPM 包,可以直接通过 NPM 来进行安装。

npm i @milkdown/core @milkdown/preset-commonmark @milkdown/theme-nord

上手也十分简单:

import { Editor } from '@milkdown/core';
import { nord } from '@milkdown/theme-nord';
import { commonmark } from '@milkdown/preset-commonmark';

Editor
  .make()
  .use(nord)
  .use(commonmark)
  .create();

我们先使用 make 来初始化编辑器,然后使用 use 来加载插件,最后使用 create 来创建编辑器。

1.3 丰富的插件

插件是 Milkdown 的核心,它本质上就是一个插件加载器,一切功能都是通过插件来提供的。表格是一个插件、主题是一个插件、甚至一行简单的文本也是一个插件。

目前官方已经提供了许多插件,确保可以开箱即用。下面仅列举了部分插件:

也可以自己动手编写插件,更多详情

二、技术栈

Milkdown 基于下面的工具实现:

  • Prosemirror:一个用于在 web 端构建富文本编辑器的工具包
  • Remark:正确的 Markdown 解析器
  • TypeScript:以 TypeScript 编写
  • Emotion:用于构建样式的强大的 css in js 工具
  • Prism:代码块支持
  • Katex:高性能的渲染数学公式

富文本编辑器本身是一个天坑。虽然 ContentEditable 看起来很美好,但实际用起来就会发现问题层出不穷。因此我们基于 Prosemirror 来实现富文本编辑器。因为它足够成熟、久经工业的锤炼,并且拥有良好的架构和 API 设计。

三、架构

Prosemirror 的核心逻辑其实类似于 React,它通过一种函数式的数据映射来体现编辑器的 UI 和内部状态的关系,如图:

编辑器通过 EditorState 来保存当前状态,并由 EditorState 产生出 EditorView,即 UI 视图。 用户在 UI 视图上进行的操作最终会产生 DOM event,例如:input 事件、click 事件。DOM event 事件会产生 Transaction,代表了对 State 的修改,类似于 Redux 或 Vuex 中的 Action。 这些 Transaction 会与原来的 EditorState 进行计算,产生新的 EditorState,如此循环。

Prosemirror 通过这样的方式将编辑器中的每个状态以 EditorState 的方式保存了下来,它是一颗树状结构。而有一点编译原理基础的朋友都知道,任何编程语言都有对应的 AST(抽象语法树)。因此我们需要的就是建立 Prosemirror 中的 EditorState 与 Markdown 的抽象语法树之间的联系。 Remark 完美契合我们的需求,因为它有设计良好的 AST,并且易于扩展自己的语法。

这样一来 Milkdown 的架构也逐渐清晰:

Markdown <-> Remark AST <-> Prosemirror State <-> UI

四、结语

在开始这个项目前,我尝试过各种各样的 Markdown 编辑器,但没有找到一款特别满意的。因为它们都是闭源,而且功能由开发商提供,有的功能太过于臃肿、有的又太过简单。 既然这样,我索性自己做一款能够轻松定制功能,非程序员也能轻松使用的 Markdown 编辑器,也就有了大家看到的 Milkdown。

希望开源的 Milkdown 让用户有更自由的选择,打破 Markdown 编辑器的“垄断”。开源不易如果 Milkdown 对您有帮助,也请给个 Star。

最后,感谢 HelloGithub 的支持和帮助。Milkdown 先是有幸入选了 第 65 期 月刊,然后受邀合作了这篇文章,让更多人知道我的开源项目。

相关推荐

搞笑句子j(搞笑句子精辟幽默专治不开心)

#我的搞笑生活#你的废话怎么比湖南卫视的广告还多啊2.我要瘦成一道闪电照亮所有猥琐的死胖子3.宁可胖的精致,也不要瘦的雷同4.秀发去无踪,头屑更出众5.心情郁闷时拿房东的牙刷刷马桶6.黄瓜在于拍,...

解决 JS 对象中继承性问题之方式一:通过原型链继承来解决继承问题

Ⅰ、继承问题:1、什么是继承?答:子类去继承父类的东西,称之为继承;如:子类继承父类的属性或方法等;2、常见的继承方式有哪些?答:继承方式有五种:其一、原型链继承;其二、构造函数继承(也称call...

西门子S7-300 SCL编程笔记(附实例)

1.数据类型:注:还有两种类型:P:POINTER(指针数据类型)。A:ANY(任何类型)数组的定义:M1:ARRAY[n0..m0,n1..m1]OFINT;数组的类型2.寻址绝对寻址符号寻...

10 个常问的 JS 面试题(js面试题目及答案)

作者:JoanneLee-(Vivi)译者:前端小智来源:medium1.如何理解JS中的`this`关键字?JS初学者总是对this关键字感到困惑,因为与其他现代编程语言相比,JS中...

js 箭头函数(js 箭头函数返回值)

js箭头函数目录一、语法基础语法高级语法实例二、注意点正文回到顶部一、语法基础语法(参数1,参数2,…,参数N)=>{函数声明}(参数1,参数2,…,参数N)=>...

JavaScript中关于null的一切(js中的null数据类型)

本文已经作者@DmitriPavluti授权翻译JavaScript有2种类型:基本类型(string,booleansnumber,symbol)和对象。对象是复杂的数据结构,JS中最简单的...

「JS 逆向百例」复杂的登录过程,最新WB逆向

声明本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!逆向目标本次的逆向目标是WB的...

三年级语文下册自测题来啦!赶紧收藏!(附答案)

2020—2021学年度下学期学业水平测试小学三年级语文试题时间60分钟;总分105分,其中试题100分,卷面分5分书写规范,卷面整洁,奖励5分;书写较认真,奖励3分;书写不认真,不得分。一、基础知识...

爬虫基础之自动化工具 DrissionPage 的使用

概述前三期文章中已经介绍到了Selenium与Playwright、Pyppeteer的使用方法,它们的功能都非常强大。而本期要讲的DrissionPage更为独特,强大,而且使用更为方...

js基础面试题92-130道题目(js面试基础知识)

92.说说你对作用域链的理解参考答案:作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。...

模拟 Vue 中 JS 动态表达式在模版中被动态解析的实现

最近在写自己的一个web框架ref-lit.js,仅仅打算自己练练手,在这个框架中,其模版语法借助了lit-html.js,而lit-html.js是通过ES2015规范中的模版字符串...

怼渣男j句子(有什么怼渣男的句子)

各位继续答题,我提前交卷了。天是蓝的,海是深的,你说的话没有一句是真的在我的世界里,你才是配角。不爱就滚,爱我的在排队。“我就是和她聊聊,没别的意思,你干嘛发火?”“我就是想给你一巴掌,没别的意思,你...

jcmd(检查梅毒挂什么门诊)

一、工具概述核心功能JDK7+提供的多功能命令行工具,用于与运行中的JVM交互,执行诊断、监控及管理操作。整合了jps、jstack、jmap等传统命令的功能,并扩展了更多诊断能力。优势特性轻量级...

3C1A四口配置,150W总功率,拆解一款电源厂新款大功率桌面充电器

前言充电头网拿到了C-SMARTLINK旭联推出的一款150W桌面充电器,这款充电器内置第三代半导体氮化镓器件,具备3C1A输出接口,USB-C1和USB-C2具备100W快充输出,USB-C3具备3...

爆发输出巅峰竟不是机炮!你对哪种开火机制情有独钟

前言在1.25.1版本当中,“极限火力”街机模式将会偕机炮坦克一起回归,在带来轻松乐趣的同时,也为后续将要登台的J系机炮轻型坦克线路做了预热。——哪里还要什么战术,配合?冲上去按住左键倾泻所有炮弹,完...