会员登录 - 用户注册 - 设为首页 - 加入收藏 - 网站地图 我熬夜开发了一款简约实用、支持多平台的Markdown在线编辑器(开源)!

我熬夜开发了一款简约实用、支持多平台的Markdown在线编辑器(开源)

时间:2025-11-05 15:51:46 来源:益强数据堂 作者:应用开发 阅读:945次

 前言

之前,熬夜一直想开发一款属于自己的开发款简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.editor

Editor.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

(责任编辑:IT科技)

上一篇:PPA仓库是专为Ubuntu用户设计的软件仓库,使用起来比其他第三方软件更容易,但是当你添加一个新的PPA仓库时,你就需要将陈旧的PPA仓库移除,具体该怎么做呢?下面随小编一起来了解下Ubuntu下如何删除PPA仓库吧。个人软件包档案(PPA)是Ubuntu独有的解决方案,允许独立开发者和贡献者构建、贡献任何定制的软件包来作为通过启动面板的第三方APT仓库。假如你是Ubuntu用户,有可能你已经增加一些流行的第三方PPA仓库到你的Ubuntu系统。假如你需要删除掉已经预先配置好的PPA仓库,下面将教你怎么做。假如你想增加一个叫“ppa:webapps/preview”第三方PPA仓库到你的系统中,如下:代码如下:$ sudo add-apt-repository ppa:webapps/preview假如你想要 单独地删除某个PPA仓库,运行下面的命令:代码如下:$ sudo add-apt-repository --remove ppa:someppa/ppa注意,上述命令不会同时删除任何已经安装或更新的软件包。假如你想要完整的删除一个PPA仓库并包括来自这个PPA安装或更新过的软件包,你需要ppa-purge命令。首先要安装ppa-purge软件包:代码如下:$ sudo apt-get install ppa-purge然后使用如下命令删除PPA仓库和与之相关的软件包:代码如下:$ sudo ppa-purge ppa:webapps/preview特别滴,在发行版更新后,当你分辨和清除已损坏的PPA仓库时这个方法特别有用!上面就是Ubuntu下删除PPA仓库的方法介绍了,本文主要是通过ppa-purge命令来删除PPA仓库,简单而又实用,且能够完整的删除PPA仓库。
下一篇:电脑突然断电(错误651的原因、常见解决方案和预防措施)
最新内容
推荐内容
  • GHOSTwin11安装方法全解析(简单易懂的安装步骤,让您快速体验Win11的新特性)
  • 域名查询之域名被墙的检测途径
  • 玩转SVN-版本回退
  • 注册域名cn好还是com域名好?cn与com大比较
  • 硬盘被水泡的后果及处理方法(遇水灾如何保护硬盘数据及修复)
  • 小白注册域名时,怎样避免落入域名陷阱?