<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          我熬夜開發(fā)了一款簡約實用、支持多平臺的Markdown在線編輯器(開...

          共 7530字,需瀏覽 16分鐘

           ·

          2021-03-09 19:50

          前言

          之前,一直想開發(fā)一款屬于自己的Markdown編輯器,主要是自己平常寫文章可以更加靈活操作,另外擴寬自己的視野也是非常不錯的選擇??!所以在周末就決定玩耍一番。首先我調研了很多線上熱門的md編輯器,都很優(yōu)秀。不為超過他們,主要自己用著舒服點。這篇文章主要是記錄下我是如何從0到1是完成一款還算拿得出手的Markdown編輯器。

          完成項目一覽

          df94dffd6df9bc10f111ca4813823087.webp

          870b01fc534e8b4fe4dc626231102e85.webp

          調研Markdown編輯器

          國內、國外關于Markdown編輯器有很多。

          • editor.md

          網(wǎng)址:https://pandao.github.io/editor.md/

          是一款開源的、可嵌入的 Markdown 在線編輯器(組件),基于 CodeMirror、jQuery 和 Marked 構建。這個組件好像是國內開發(fā)的,個人之前用著還可以。

          • typora

          網(wǎng)址:https://www.typora.io/

          Typora是一款免費的輕量級Markdown編輯器,它沒有Mou,Haroopad等Markdown編輯器那么大名鼎鼎,算是較為小眾的一款產(chǎn)品。憑良心說話,我用過的Markdown編輯器也有好幾款,其中包括:小書匠,Haroopad,Atom等,但Typora是最合我心意的一款編輯器了,其輕量、快速、易于上手,使用起來簡直不要太舒服??!

          • tui-editor

          網(wǎng)址:https://ui.toast.com/tui-editor

          這是一款Markdown組件,通過調研決定用它。為什么?確認過眼神~

          技術棧

          • Vue.js

          • tui-editor

          實戰(zhàn)

          確定好技術棧之后,我們就得腳踏實地地干活了。

          1. 搭建Vue腳手架

          我們會使用VueCLI搭建一個最基礎的項目,這里暫時不需要Vue-router、Vuex這些插件,所以盡可能輕裝。

          2. 創(chuàng)建編輯器組件

          我們會在components文件目錄下創(chuàng)建一個Editor.vue文件,這個文件也就是我們的主戰(zhàn)場,大部分操作都會在這個文件。

          3. 配置編輯器組件

          在配置編輯器時,有以下幾點使我非常困惑,以致于花費了大量時間。

          1. 代碼沒有被高亮

          2. 語言不是中文

          3. 編輯器樣式有問題

          以上這幾個問題通過以下措施才得以解決:

          1. 通過閱讀文檔:https://nhn.github.io/tui.editor/latest/

          2. 訪問Github網(wǎng)站: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"; // Editor's Dependency Style
          import "@toast-ui/editor/dist/toastui-editor.css"; // Editor's 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>

          看似上面幾行代碼,但是也是很費勁才得以完成。

          增加功能

          首先,我開發(fā)這個程序的初衷是更好地方便自己寫文章,所以,我定下了這幾個需求:

          1. 可復制HTML格式文本,方便復制到微信公眾號

          2. 可復制Markdown文本,方便可以復制到稀土掘金、csdn這些博客網(wǎng)站上發(fā)布

          3. 可下載Markdown文件,更加方便保存和移動

          因篇幅原因,先奉上主要邏輯代碼。這里我使用了clipboard這個將文本復制到剪貼板的插件。網(wǎng)址:https://clipboardjs.com/。
          另外,downloadBlobAsFile方法主要是創(chuàng)建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"; // Editor's Dependency Style
          import "@toast-ui/editor/dist/toastui-editor.css"; // Editor's Style
          import "@/styles/index.css";
          export default {
          components: {},
          data() {
          return {
          editor: null,
          drawer: false,
          aboutView: false,
          functionList:['頁面簡約','功能實用','支持稀土掘金、CSDN、微信公眾號、知乎','可復制HTML、MarkDown','可下載MarkDown文件'],
          authorList:['作者:Vam的金豆之路','歡迎關注我的公眾號:前端歷劫之路','我創(chuàng)建了一個技術交流、文章分享群,群里有很多大廠的前端大佬,關注公眾號后,點擊下方菜單了解更多即可加我微信,期待你的加入']
          };
          },
          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>

          針對微信公眾號進行樣式優(yōu)化

          ::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

          如果對你有幫助,歡迎Star~




          33d74eae040d8562421bb8e211e0e4d1.webp

          瀏覽 81
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久一卡二卡 | 亚洲一本在线 | 欧美干逼 | 毛片大香蕉| 国产精品久草 |