您现在的位置是:亿华云 > IT科技类资讯
我熬夜开发了一款简约实用、支持多平台的Markdown在线编辑器(开源)
亿华云2025-10-03 02:07:57【IT科技类资讯】2人已围观
简介前言之前,一直想开发一款属于自己的Markdown编辑器,主要是自己平常写文章可以更加灵活操作,另外扩宽自己的视野也是非常不错的选择啊!所以在周末就决定玩耍一番。首先我调研了很多线上热门的md编辑器,
前言
之前,熬夜一直想开发一款属于自己的开发款简Markdown编辑器,主要是约实用支源自己平常写文章可以更加灵活操作,另外扩宽自己的持多视野也是非常不错的选择啊!所以在周末就决定玩耍一番。首先我调研了很多线上热门的平台md编辑器,都很优秀。编辑不为超过他们,器开主要自己用着舒服点。熬夜这篇文章主要是开发款简记录下我是如何从0到1是完成一款还算拿得出手的Markdown编辑器。
完成项目一览


调研Markdown编辑器
国内、约实用支源国外关于Markdown编辑器有很多。持多
editor.md
网址:https://pandao.github.io/editor.md/
是平台一款开源的、可嵌入的编辑 Markdown 在线编辑器(组件),基于 CodeMirror、器开jQuery 和 Marked 构建。熬夜这个组件好像是国内开发的,个人之前用着还可以。
typora
网址:https://www.typora.io/
Typora是一款免费的源码库轻量级Markdown编辑器,它没有Mou,Haroopad等Markdown编辑器那么大名鼎鼎,算是较为小众的一款产品。凭良心说话,我用过的Markdown编辑器也有好几款,其中包括:小书匠,Haroopad,Atom等,但Typora是最合我心意的一款编辑器了,其轻量、快速、易于上手,使用起来简直不要太舒服!!
tui-editor
网址:https://ui.toast.com/tui-editor
这是一款Markdown组件,通过调研决定用它。为什么?确认过眼神~
技术栈
Vue.js tui-editor实战
确定好技术栈之后,我们就得脚踏实地地干活了。
1. 搭建Vue脚手架
我们会使用VueCLI搭建一个最基础的项目,这里暂时不需要Vue-router、Vuex这些插件,所以尽可能轻装。
2. 创建编辑器组件
我们会在components文件目录下创建一个Editor.vue文件,这个文件也就是我们的主战场,大部分操作都会在这个文件。服务器租用
3. 配置编辑器组件
在配置编辑器时,有以下几点使我非常困惑,以致于花费了大量时间。
代码没有被高亮 语言不是中文 编辑器样式有问题以上这几个问题通过以下措施才得以解决:
通过阅读文档:https://nhn.github.io/tui.editor/latest/ 访问Github网站:https://github.com/nhn/tui.editorEditor.vue
<template> <div class="main"> <div id="editor"></div> </div> </template> <script> import Editor from "@toast-ui/editor"; import hljs from "highlight.js"; import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight"; import @toast-ui/editor/dist/i18n/zh-cn.js; import "highlight.js/styles/github.css"; import "codemirror/lib/codemirror.css"; // Editors Dependency Style import "@toast-ui/editor/dist/toastui-editor.css"; // Editors Style import "@/styles/index.css"; export default { components: { }, data() { return { editor: null }; }, mounted() { this.editor = new Editor({ el: document.getElementById("editor"), plugins: [[codeSyntaxHighlight, { hljs}]], previewStyle: "vertical", height: "100vh", initialEditType: "markdown", minHeight: "200px", initialValue: "", placeholder: "你想写点什么...", language:zh-CN, useCommandShortcut: true, useDefaultHTMLSanitizer: true, usageStatistics: false, hideModeSwitch: false, viewer: true, toolbarItems: [ "heading", "bold", "italic", "strike", "divider", "hr", "quote", "divider", "ul", "ol", "task", "indent", "outdent", "divider", "table", "image", "link", "divider", "code", "codeblock", ], }); this.editor.getUI().getToolbar().removeItem("21"); }, }; </script>看似上面几行代码,但是也是很费劲才得以完成。
增加功能
首先,我开发这个程序的初衷是更好地方便自己写文章,所以,我定下了这几个需求:
可复制HTML格式文本,方便复制到微信公众号 可复制Markdown文本,方便可以复制到稀土掘金、csdn这些博客网站上发布 可下载Markdown文件,更加方便保存和移动因篇幅原因,先奉上主要逻辑代码。这里我使用了clipboard这个将文本复制到剪贴板的插件。网址:https://clipboardjs.com/。
另外,downloadBlobAsFile方法主要是创建Blob对象,然后通过a标签的download属性进行下载。
downloadBlobAsFile.js
export default function downloadBlobAsFile(data, filename) { const contentType = application/octet-stream; if (!data) { console.error( No data); return; } if (!filename) { filename = filetodonwload.txt; } if (typeof data === object) { data = JSON.stringify(data, undefined, 4); } let blob = new Blob([data], { type: contentType}); let e = document.createEvent(MouseEvents); let a = document.createElement(a); a.download = filename; a.href = URL.createObjectURL(blob); a.dataset.downloadurl = [contentType, a.download, a.href].join(:); e.initMouseEvent(click, true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); a.dispatchEvent(e); }Editor.vue
<template> <div class="main"> <div class="tools"> <el-button size="mini" type="primary" @click="drawer = true" >工具</el-button> <el-button size="mini" type="primary" @click="aboutView = true" >关于</el-button> <el-dialog :title="工具" :visible.sync="drawer" :append-to-body="true" > <div class="tool-innter"> <el-button type="primary" @click="getHtml" class="htmlbtn" >复制HTML </el-button > <el-button type="primary" @click="getMd" class="mdbtn" >复制MarkDown </el-button > <el-button type="primary" @click="downloadMd" class="downloadbtn" >下载MarkDown </el-button > </div> </el-dialog> <el-dialog :title="关于" :visible.sync="aboutView" :append-to-body="true" > <h3>Simple·MarkDown编辑器</h3> <ul class="functionList"> <li v-for="(item,index) in functionList" :key="index"> { { item}} </li> </ul> <h3>作者</h3> <ul class="functionList"> <li v-for="(item,index) in authorList" :key="index">{ { item}}</li> </ul> <div class="wxcode"> <img src="../assets/wxcode.jpeg" alt=""> </div> </el-dialog> </div> <div id="editor"></div> </div> </template> <script> import Editor from "@toast-ui/editor"; import Clipboard from "clipboard"; import hljs from "highlight.js"; import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight"; import @toast-ui/editor/dist/i18n/zh-cn.js; import downloadBlobAsFile from "../utils/download"; import "highlight.js/styles/github.css"; //https://github.com/highlightjs/highlight.js/tree/master/src/styles import "codemirror/lib/codemirror.css"; // Editors Dependency Style import "@toast-ui/editor/dist/toastui-editor.css"; // Editors Style import "@/styles/index.css"; export default { components: { }, data() { return { editor: null, drawer: false, aboutView: false, functionList:[页面简约,功能实用,支持稀土掘金、CSDN、微信公众号、知乎,可复制HTML、MarkDown,可下载MarkDown文件], authorList:[作者:Vam的金豆之路,欢迎关注我的服务器托管公众号:前端历劫之路,我创建了一个技术交流、文章分享群,群里有很多大厂的前端大佬,关注公众号后,点击下方菜单了解更多即可加我微信,期待你的加入] }; }, methods: { // 复制HTML getHtml() { const clipboard = new Clipboard(".htmlbtn", { target: () => this.editor.preview.el, }); clipboard.on("success", () => { this.$message({ message: "复制成功", type: "success", }); clipboard.destroy(); }); clipboard.on("error", () => { this.$message.error("复制失败"); clipboard.destroy(); }); }, // 复制Markdown getMd() { const clipboard = new Clipboard(".mdbtn", { text: () => this.editor.getMarkdown(), }); clipboard.on("success", () => { this.$message({ message: "复制成功", type: "success", }); clipboard.destroy(); }); clipboard.on("error", () => { this.$message.error("复制失败"); clipboard.destroy(); }); }, // 下载Markdown downloadMd() { if (this.editor.getMarkdown().trim()) { downloadBlobAsFile(this.editor.getMarkdown(), "unnamed.md"); } else { this.$message.error("下载失败"); } }, }, mounted() { this.editor = new Editor({ el: document.getElementById("editor"), plugins: [[codeSyntaxHighlight, { hljs}]], previewStyle: "vertical", height: "100vh", initialEditType: "markdown", minHeight: "200px", initialValue: "", placeholder: "你想写点什么...", language:zh-CN, useCommandShortcut: true, useDefaultHTMLSanitizer: true, usageStatistics: false, hideModeSwitch: false, viewer: true, toolbarItems: [ "heading", "bold", "italic", "strike", "divider", "hr", "quote", "divider", "ul", "ol", "task", "indent", "outdent", "divider", "table", "image", "link", "divider", "code", "codeblock", ], }); this.editor.getUI().getToolbar().removeItem("21"); }, }; </script>针对微信公众号进行样式优化
::v-deep是深度作用选择器,主要是为了覆盖原有的样式所用。
::v-deep ul li { list-style-type: disc !important; } ::v-deep ol li { list-style-type: decimal !important; } ::v-deep ul li::before, ::v-deep ol li::before { content: none; } ::v-deep .tui-editor-contents p>code{ background-color: #fff5f5; color: #ff502c; } ::v-deep .tui-editor-contents pre { width: 100%; overflow: auto; }线上体验
https://www.maomin.club/site/mdeditor/
结语
谢谢阅读,希望没有浪费你的时间。
源码地址:
https://github.com/maomincoding/simpleMdEditor
很赞哦!(56)