成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

[[385871]]

 前言

之前,一直想開發一款屬于自己的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. 配置編輯器組件

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

  1. 代碼沒有被高亮
  2. 語言不是中文
  3. 編輯器樣式有問題

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

  1. 通過閱讀文檔:https://nhn.github.io/tui.editor/latest/
  2. 訪問Github網站:https://github.com/nhn/tui.editor

Editor.vue

  1. <template> 
  2.   <div class="main"
  3.     <div id="editor"></div> 
  4.   </div> 
  5. </template> 
  6. <script> 
  7. import Editor from "@toast-ui/editor"
  8. import hljs from "highlight.js"
  9. import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight"
  10. import '@toast-ui/editor/dist/i18n/zh-cn.js'
  11.  
  12. import "highlight.js/styles/github.css"
  13. import "codemirror/lib/codemirror.css"; // Editor's Dependency Style 
  14. import "@toast-ui/editor/dist/toastui-editor.css"; // Editor's Style 
  15. import "@/styles/index.css"
  16. export default { 
  17.   components: {}, 
  18.   data() { 
  19.     return { 
  20.       editor: null 
  21.     }; 
  22.   }, 
  23.   mounted() { 
  24.     this.editor = new Editor({ 
  25.       el: document.getElementById("editor"), 
  26.       plugins: [[codeSyntaxHighlight, {hljs}]], 
  27.       previewStyle: "vertical"
  28.       height: "100vh"
  29.       initialEditType: "markdown"
  30.       minHeight: "200px"
  31.       initialValue: ""
  32.       placeholder: "你想寫點什么..."
  33.       language:'zh-CN'
  34.       useCommandShortcut: true
  35.       useDefaultHTMLSanitizer: true
  36.       usageStatistics: false
  37.       hideModeSwitch: false
  38.       viewer: true
  39.       toolbarItems: [ 
  40.         "heading"
  41.         "bold"
  42.         "italic"
  43.         "strike"
  44.         "divider"
  45.         "hr"
  46.         "quote"
  47.         "divider"
  48.         "ul"
  49.         "ol"
  50.         "task"
  51.         "indent"
  52.         "outdent"
  53.         "divider"
  54.         "table"
  55.         "image"
  56.         "link"
  57.         "divider"
  58.         "code"
  59.         "codeblock"
  60.       ], 
  61.     }); 
  62.     this.editor.getUI().getToolbar().removeItem("21"); 
  63.   }, 
  64. }; 
  65. </script> 

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

增加功能

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

  1. 可復制HTML格式文本,方便復制到微信公眾號
  2. 可復制Markdown文本,方便可以復制到稀土掘金、csdn這些博客網站上發布
  3. 可下載Markdown文件,更加方便保存和移動

因篇幅原因,先奉上主要邏輯代碼。這里我使用了clipboard這個將文本復制到剪貼板的插件。網址:https://clipboardjs.com/。

另外,downloadBlobAsFile方法主要是創建Blob對象,然后通過a標簽的download屬性進行下載。

downloadBlobAsFile.js

  1. export default function downloadBlobAsFile(data, filename) { 
  2.     const contentType = 'application/octet-stream'
  3.     if (!data) { 
  4.         console.error(' No data'); 
  5.         return
  6.     } 
  7.  
  8.     if (!filename) { 
  9.         filename = 'filetodonwload.txt'
  10.     } 
  11.  
  12.     if (typeof data === 'object') { 
  13.         data = JSON.stringify(data, undefined, 4); 
  14.     } 
  15.  
  16.     let blob = new Blob([data], {type: contentType}); 
  17.     let e = document.createEvent('MouseEvents'); 
  18.     let a = document.createElement('a'); 
  19.  
  20.     a.download = filename; 
  21.     a.href = URL.createObjectURL(blob); 
  22.     a.dataset.downloadurl = [contentType, a.download, a.href].join(':'); 
  23.     e.initMouseEvent('click'truefalse, window, 0, 0, 0, 0, 0, falsefalsefalsefalse, 0, null); 
  24.     a.dispatchEvent(e); 

Editor.vue

  1. <template> 
  2.   <div class="main"
  3.     <div class="tools"
  4.       <el-button 
  5.           size="mini" 
  6.           type="primary" 
  7.           @click="drawer = true" 
  8.       >工具</el-button> 
  9.       <el-button 
  10.           size="mini" 
  11.           type="primary" 
  12.           @click="aboutView = true" 
  13.       >關于</el-button> 
  14.       <el-dialog 
  15.           :title="'工具'" 
  16.           :visible.sync="drawer" 
  17.           :append-to-body="true" 
  18.       > 
  19.         <div class="tool-innter"
  20.           <el-button type="primary" @click="getHtml" class="htmlbtn" 
  21.           >復制HTML 
  22.           </el-button 
  23.           > 
  24.           <el-button type="primary" @click="getMd" class="mdbtn" 
  25.           >復制MarkDown 
  26.           </el-button 
  27.           > 
  28.           <el-button type="primary" @click="downloadMd" class="downloadbtn" 
  29.           >下載MarkDown 
  30.           </el-button 
  31.           > 
  32.         </div> 
  33.       </el-dialog> 
  34.       <el-dialog 
  35.           :title="'關于'" 
  36.           :visible.sync="aboutView" 
  37.           :append-to-body="true" 
  38.       > 
  39.         <h3>Simple·MarkDown編輯器</h3> 
  40.         <ul class="functionList"
  41.           <li v-for="(item,index) in functionList" :key="index"
  42.             {{item}} 
  43.           </li> 
  44.         </ul> 
  45.         <h3>作者</h3> 
  46.         <ul class="functionList"
  47.           <li v-for="(item,index) in authorList" :key="index">{{item}}</li> 
  48.         </ul> 
  49.         <div class="wxcode"
  50.           <img src="../assets/wxcode.jpeg" alt=""
  51.         </div> 
  52.       </el-dialog> 
  53.     </div> 
  54.     <div id="editor"></div> 
  55.   </div> 
  56. </template> 
  57. <script> 
  58. import Editor from "@toast-ui/editor"
  59. import Clipboard from "clipboard"
  60. import hljs from "highlight.js"
  61. import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight"
  62. import '@toast-ui/editor/dist/i18n/zh-cn.js'
  63. import downloadBlobAsFile from "../utils/download"
  64.  
  65. import "highlight.js/styles/github.css"; //https://github.com/highlightjs/highlight.js/tree/master/src/styles 
  66. import "codemirror/lib/codemirror.css"; // Editor's Dependency Style 
  67. import "@toast-ui/editor/dist/toastui-editor.css"; // Editor's Style 
  68. import "@/styles/index.css"
  69. export default { 
  70.   components: {}, 
  71.   data() { 
  72.     return { 
  73.       editor: null
  74.       drawer: false
  75.       aboutView: false
  76.       functionList:['頁面簡約','功能實用','支持稀土掘金、CSDN、微信公眾號、知乎','可復制HTML、MarkDown','可下載MarkDown文件'], 
  77.       authorList:['作者:Vam的金豆之路','歡迎關注我的公眾號:前端歷劫之路','我創建了一個技術交流、文章分享群,群里有很多大廠的前端大佬,關注公眾號后,點擊下方菜單了解更多即可加我微信,期待你的加入'
  78.     }; 
  79.   }, 
  80.   methods: { 
  81.     // 復制HTML 
  82.     getHtml() { 
  83.       const clipboard = new Clipboard(".htmlbtn", { 
  84.         target: () => this.editor.preview.el, 
  85.       }); 
  86.       clipboard.on("success", () => { 
  87.         this.$message({ 
  88.           message: "復制成功"
  89.           type: "success"
  90.         }); 
  91.         clipboard.destroy(); 
  92.       }); 
  93.       clipboard.on("error", () => { 
  94.         this.$message.error("復制失敗"); 
  95.         clipboard.destroy(); 
  96.       }); 
  97.     }, 
  98.     // 復制Markdown 
  99.     getMd() { 
  100.       const clipboard = new Clipboard(".mdbtn", { 
  101.         text: () => this.editor.getMarkdown(), 
  102.       }); 
  103.       clipboard.on("success", () => { 
  104.         this.$message({ 
  105.           message: "復制成功"
  106.           type: "success"
  107.         }); 
  108.         clipboard.destroy(); 
  109.       }); 
  110.       clipboard.on("error", () => { 
  111.         this.$message.error("復制失敗"); 
  112.         clipboard.destroy(); 
  113.       }); 
  114.     }, 
  115.     // 下載Markdown 
  116.     downloadMd() { 
  117.       if (this.editor.getMarkdown().trim()) { 
  118.         downloadBlobAsFile(this.editor.getMarkdown(), "unnamed.md"); 
  119.       } else { 
  120.         this.$message.error("下載失敗"); 
  121.       } 
  122.     }, 
  123.   }, 
  124.   mounted() { 
  125.     this.editor = new Editor({ 
  126.       el: document.getElementById("editor"), 
  127.       plugins: [[codeSyntaxHighlight, {hljs}]], 
  128.       previewStyle: "vertical"
  129.       height: "100vh"
  130.       initialEditType: "markdown"
  131.       minHeight: "200px"
  132.       initialValue: ""
  133.       placeholder: "你想寫點什么..."
  134.       language:'zh-CN'
  135.       useCommandShortcut: true
  136.       useDefaultHTMLSanitizer: true
  137.       usageStatistics: false
  138.       hideModeSwitch: false
  139.       viewer: true
  140.       toolbarItems: [ 
  141.         "heading"
  142.         "bold"
  143.         "italic"
  144.         "strike"
  145.         "divider"
  146.         "hr"
  147.         "quote"
  148.         "divider"
  149.         "ul"
  150.         "ol"
  151.         "task"
  152.         "indent"
  153.         "outdent"
  154.         "divider"
  155.         "table"
  156.         "image"
  157.         "link"
  158.         "divider"
  159.         "code"
  160.         "codeblock"
  161.       ], 
  162.     }); 
  163.     this.editor.getUI().getToolbar().removeItem("21"); 
  164.   }, 
  165. }; 
  166. </script> 

針對微信公眾號進行樣式優化

::v-deep是深度作用選擇器,主要是為了覆蓋原有的樣式所用。

  1. ::v-deep ul li { 
  2.   list-style-type: disc !important; 
  3.  
  4. ::v-deep ol li { 
  5.   list-style-type: decimal !important; 
  6.  
  7. ::v-deep ul li::before, ::v-deep ol li::before { 
  8.   content: none; 
  9. ::v-deep .tui-editor-contents p>code{ 
  10.   background-color: #fff5f5; 
  11.   color: #ff502c; 
  12. ::v-deep .tui-editor-contents pre { 
  13.   width: 100%; 
  14.   overflow: auto; 

線上體驗

https://www.maomin.club/site/mdeditor/

結語

謝謝閱讀,希望沒有浪費你的時間。

源碼地址:

https://github.com/maomincoding/simpleMdEditor

 

責任編輯:姜華 來源: 前端歷劫之路
相關推薦

2023-06-20 00:04:18

框架開發UMD

2020-09-18 06:00:51

開源Markdown編輯器

2021-11-24 09:12:11

Markdown編輯器Linux

2020-09-16 10:27:50

MarkDown編輯器編程

2024-03-06 08:26:29

2021-08-26 05:15:22

圖片編輯器 H5-DooringMitu-Doorin

2022-08-31 08:32:22

數據可視化項目nocode

2017-05-23 19:19:16

開源Markdown編輯器

2021-10-21 10:58:03

Markdown編輯器

2021-10-27 14:55:57

Mark TextMarkdown編輯器

2022-04-27 08:42:20

Markdown編輯神器

2021-04-08 14:58:59

開發前端編輯器

2021-06-23 06:12:38

Subtitld編輯器開源

2022-09-05 13:16:42

MicroVim編輯器

2021-04-04 08:16:09

NewsFlash閱讀器開源

2023-09-10 23:22:33

Zettlr筆記編輯器

2022-01-10 18:16:24

編輯器Typora Markdown

2021-04-12 08:31:53

PC-Dooring項目PC端搭建

2015-06-01 07:37:42

開發產品

2021-12-23 10:59:30

開源技術 軟件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产黄色av网站 | 99久久精品国产一区二区三区 | 国产精品一区二区三区四区 | 91综合在线视频 | 免费亚洲成人 | 天天人人精品 | 一级少妇女片 | 日日天天 | 亚洲天堂一区二区 | 久久精品欧美电影 | 免费高清av | 伊人久久精品一区二区三区 | 91免费入口 | 国产在线一区二 | 国产一区二区在线播放视频 | 能看的av | 国产精品视频免费看 | 视频一区二区中文字幕日韩 | 色综合一区二区 | 日韩欧美一级精品久久 | 久久成人精品一区二区三区 | 正在播放国产精品 | av在线播放网站 | 久久久精品久 | 亚洲精品视频一区二区三区 | 黄色网址免费在线观看 | 毛片免费在线观看 | 日本不卡一区 | 中文日韩在线视频 | 又黄又爽的网站 | 精品国产一二三区 | 欧美成人一级 | 亚洲一区中文字幕 | 国产精品美女久久久久久久久久久 | 日韩精品一区二区三区在线观看 | 色综合中文 | 精品视频一区二区在线观看 | 国产精品s色 | 中文字幕在线看 | 97人人干| 成人精品网 |