一款使用marked和highlight.js開發的一款markdown編輯器,除常見markdown語法外,支持快捷輸入、圖片粘貼、代碼複製、全屏編輯、預覽等功能。javascript
使用起來簡單方便,只需幾行代碼,便可在你的頁面上引入一個markdown編輯器,編輯區支持像專業編輯器那樣。php
編輯器涵蓋了經常使用的markdown編輯器功能,可經過已有屬性進行配置,對編輯器功能和樣式進行基本的配置,也可根據需求進行深度定製。css
示例 html
經過監聽文本輸入區域內內容的變化,實時將輸入的markdown語法進行編譯,並渲染到預覽區域。vue
編輯器大體分爲頭部菜單欄、左側內容輸入區域、右側預覽區域三個部分。 頭部菜單主要爲定自定義標題區域和菜單按鈕,菜單按鈕可經過配置文件進行顯示和隱藏;左側編輯區域,簡單版使用textarea開發,知足基本需求, 專業版使用codemirror開發,編輯區域支持手動輸入文本和經過頭部菜單插入;右側預覽區域可實時預覽輸入文本,並可經過菜單按鈕,進行編輯區域和預覽區域的切換。java
npm i -S vue-meditor
複製代碼
git clone https://github.com/zhaoxuhui1122/vue-markdown.git
複製代碼
簡單版python
import Markdown from 'vue-meditor'
複製代碼
專業版react
import { MarkdownPro } from 'vue-meditor'
複製代碼
預覽組件git
import { MarkdownPreview } from 'vue-meditor'
複製代碼
簡單版github
import Markdown from '@/components/markdown/...';
複製代碼
專業版
import MarkdownPro from '@/components/markdown/pro';
複製代碼
預覽組件
import MarkdownPreview from '@/components/markdown/preview';
複製代碼
<template>
<div class="markdown">
<Markdown/>
</div>
</template>
<script>
import Markdown from 'vue-meditor';
export default {
name: "markdown",
components: {
Markdown
}
}
</script>
複製代碼
String/Number
''
編輯器輸入的文本,支持經過v-dodel
數據雙向綁定設置編輯器內容和獲取編輯器的值。
String/Number
auto
編輯器的初始化寬度。
Number
600
編輯器的初始化高度。
Boolean
true
編輯器是否含有邊框。
Object
參見下表
頭部菜單按鈕,經過設置true or false控制決定是否顯示,目前配置支持持控制按鈕顯示隱藏,後續將支持根據配置顯示排列順序。
名稱 | 說明 | 默認是否顯示 |
---|---|---|
strong | 粗體 | 是 |
italic | 斜體 | 是 |
overline | 刪除線 | 是 |
h1 | 標題1 | 是 |
h2 | 標題2 | 是 |
h3 | 標題3 | 是 |
h4 | 標題4 | 否 |
h5 | 標題5 | 否 |
h6 | 標題6 | 否 |
hr | 分割線 | 是 |
quote | 引用 | 是 |
ul | 無序列表 | 是 |
ol | 有序列表 | 是 |
code | 代碼塊 | 是 |
link | 連接 | 是 |
image | image | 是 |
table | 表格 | 是 |
checked | 已完成列表 | 是 |
notChecked | 未完成列表 | 是 |
preview | 預覽 | 是 |
split | 分屏模式切換 | 是 |
打印 | 否 | |
theme | 主題切換 | 是 |
fullscreen | 全屏 | 是 |
exportmd | 導出爲*.md文件 | 是 |
importmd | 導入本地*.md文件 | 是 |
save | 保存按鈕 | 否 |
clear | 清空內容 | 否 |
String
light
編輯器代碼塊主題,目前支持light
、dark
、oneDark
、gitHub
四種代碼塊風格,可經過自定義theme並修改樣式文件進行主題定製。
自定義theme時,預覽區域的會增長一個爲markdown-theme-[theme]
的class
。
Boolean
false
是否開啓自動保存,設置爲開啓時可經過綁定on-save
事件獲取編輯器內的值和代碼塊主題。
<Markdown @on-save="handleOnSave"/>
複製代碼
handleOnSave({value, theme}){
console.log(value, theme);
}
複製代碼
Number
10000
自動保存間隔時間,單位:mm
,默認10000mm,須要autoSave = true
時纔有效。
String
unnamed
導出的md文件名稱,默認unnamed.md。
Object
{}
marked配置項,能夠根據需求自定義。
<Markdown :markedOptions="{baseUrl:'http://***.oss-cn-shanghai.aliyuncs.com/'}"/>
複製代碼
Boolean
false
是不是預覽模式,開啓時可做爲一個預覽組件使用,與預覽組件功能一致。
Boolean
true
是否支持複製代碼塊內的內容。
String
複製代碼
複製代碼按鈕顯示文字。
String/Number
''
預覽組件初始化內容,支持動態更新。
String
light
代碼塊主題,與編輯器編輯器代碼塊主題一致。
Object
{}
marked配置項,與編輯器內該配置一致。
Boolean
true
是否支持複製代碼塊內的內容。
String
複製代碼
複製代碼按鈕顯示文字。
編輯器初始化完成時觸發,返回值爲Object
,包含組件自己和insertContent
方法。
編輯器保存事件,自動保存或者手動保存時觸發,支持ctrl+s
或command+s
觸發保存,返回值類型爲Object
,包含當前輸入值value
和選擇的代碼塊主題theme
。
監聽編輯器粘貼圖片事件,在編輯區域內手動粘貼圖片時觸發,可用於支持粘貼插入圖片文件,返回file
文件,上傳文件後可結合on-ready
事件內返回的insertContent
插入圖片。
複製代碼塊內容,觸發時返回當前代碼塊的text,copyCode開啓時纔有效。
on-paste-image
雖然能夠支持圖片粘貼事件的監聽,但不會處理圖片上傳至服務器並將連接插入編輯器這段邏輯。
目前若是想要支持粘貼插入圖片,須要在on-paste-image
方法裏上傳圖片文件,拿到圖片地址後,使用on-ready
方法裏返回的insertContent方法插入圖片。
上述操做顯得過於複雜,能夠直接在源碼裏擴展mixins裏的handlePaste
方法,圖片上傳完成後,直接調用this.insertContent
方法插入圖片。
修改/markdown/mixins/common.js
handlePaste(_, e) {// 粘貼圖片
const { clipboardData = {} } = e;
const { types = [], items } = clipboardData;
let item = null;
for (let i = 0; i < types.length; i++) {
if (types[i] === 'Files') {
item = items[i];
break;
}
}
if (item) {
const file = item.getAsFile();
if (/image/gi.test(file.type)) {
e.preventDefault();
// 1.上傳操做
// 2.插入圖片 this.insertContent(`![image](imgUrl)`)
}
}
}
複製代碼
目前編輯器只支持常見code語法,若是須要實現如流程圖等功能,須要進一步擴展,以實現一個簡單的流程圖爲例,具體實現思路以下:
默認狀況下,markedjs會使用renderer.code方法對輸入的代碼塊進行解析,並會藉助highlight.js
支持語法高亮。 能夠將流程圖語法輸入到代碼塊內,並標明語言,重寫marked.Renderer的code解析方法,結合結合flowchart.js
路程圖代碼進行解析,返回文本內容。
修改`/markdown/libs/js/simple.js
import hljs from './hljs';
import index from 'index';
import {parse} from 'flowchart.js'
hljs.initHighlightingOnLoad();
const renderer = new index.Renderer();
renderer.code = (code, language) => {
if (language === 'flow') {// 流程圖
const dom = document.createElement('div');
const flowchart = parse(code);
flowchart.drawSVG(dom, {/*相關配置*/});
return dom.innerHTML;
} else {// 默認解析
return `<pre class="hljs"><code class="${language}">${hljs.highlightAuto(code).value}</code></pre>`
}
}
export default index.setOptions({
renderer,
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true,
highlight: function (code) {
return hljs.highlightAuto(code).value;
}
})
複製代碼
項目內使用的`index.js均爲其默認配置功能,如須要特殊轉換,可重寫其內部的解析方法,即重寫其renderer相關方法 參考文檔。
預覽區域和文檔預覽組件暫不支持自動生成目錄,實現自動生成目錄思路目前想到的大體有
renderer.heading
方法,爲生成的標題添加id,輸入特定快捷鍵,如[TOC]
時,查找預覽區域內的的全部標題標籤,分析等級關係,生成目錄標籤項目內全部的icon和命名參考/assets/font/index.html
,替換時需注意,預覽區域的checkbox爲icon,注意一併替換, 修改/assets/css/index.less
內的input[type="checkbox"]
的:after
樣式。
npm包構建時,三個組件徹底獨立,沒有抽離公共文件,因此,當同一個項目內引入其中的兩個或三個組件都引入時,存在必定的重複代碼, 主要爲highlight.js
、marked
、iconfont
、css樣式幾個部分。
解決方式:將組件複製到本地項目,打包時將這些文件做爲公共文件抽離出來。
注意:三個組件中使用的iconfont爲同一套,若是隻是單純的使用preview
組件, 將會引入整個項目所使用的iconfont,可刪除iconfont的引入, 重寫input[type="checkbox"]
的樣式,preview組件體積將會減小一半,樣式文件位於markdown/assets/css/index.less
。
codemirror主要分爲主文件、mode相關文件和樣式文件,主文件體積異常的大,mode文件目前只選用了css/jsvascript/markdown/meta/xml五個文件, 其中markdown.js和meta.js爲必須引用的,項目中已將常見的編程語言代碼風格定義爲css/js/xml之一,例如less/sass/scss按照css規則解析,html/vue按照xml規則解析。 優化可從一下方面入手
highlight.js本來體積也是較大的,主要緣由爲,編譯時爲支持各類代碼語言,引入了相應的解析文件, 項目內已根據常見的代碼語言進行了一次篩選,進行按需引入,可根據自身需求,再次對引用文件進行刪減
參見src/markdown/libs/js/hljs.js
,目前支持的語言有
import hljs from 'highlight.js/lib/highlight'
import javascript from 'highlight.js/lib/languages/javascript'
import java from 'highlight.js/lib/languages/java';
import css from 'highlight.js/lib/languages/css';
import less from 'highlight.js/lib/languages/less';
import go from 'highlight.js/lib/languages/go';
import markdown from src;
import php from 'highlight.js/lib/languages/php';
import python from 'highlight.js/lib/languages/python';
import ruby from 'highlight.js/lib/languages/ruby';
import stylus from 'highlight.js/lib/languages/stylus';
import typescript from 'highlight.js/lib/languages/typescript';
import xml from 'highlight.js/lib/languages/xml';
const languages = {
javascript,
java,
css,
less,
markdown,
go,
php,
python,
ruby,
stylus,
typescript,
xml
}
Object.keys(languages).forEach(key => {
hljs.registerLanguage(key, languages[key])
})
export default hljs;
複製代碼
優化思路:無
只須要preview組件時,避免引入全部icon,參考功能擴展裏icon替換方法。
對於功能上的缺陷、使用方法和但願擴展的功能,能夠提 Issues。