簡介
一款使用marked和highlight.js開發的一款markdown編輯器,除常見markdown語法外,支持快捷輸入、圖片粘貼、代碼復制、全屏編輯、預覽等功能。
使用起來簡單方便,只需幾行代碼,即可在你的頁面上引入一個markdown編輯器,編輯區支持像專業編輯器那樣。
編輯器涵蓋了常用的markdown編輯器功能,可通過已有屬性進行配置,對編輯器功能和樣式進行基本的配置,也可根據需求進行深度定制。
項目地址
文檔地址
示例
特點
- 使用簡單,只需要安裝npm包,引入項目即可使用,不需要繁瑣的初始化配置。
- 方便擴展,根據實際需求,支持常見的功能配置,也可根據實際需求進行深度定制。
- 體積小,加載速度快,npm包刪除了highlight.js和codemirror里的依賴。
- 靈活的主題,默認支持四種代碼塊風格,也可根據實際需求定制自己的主題樣式
- 功能強大,支持專業版的編輯器,使用codemirror實現編輯窗口,可識別markdown語法
- 鍵盤事件監聽,如保存、粘貼、回車時上次輸入語法判斷等
- 可擴展性強,除了提供的屬性配置編輯器,也可直接在原有組件基礎上進行二次開發
實現思路
通過監聽文本輸入區域內內容的變化,實時將輸入的markdown語法進行編譯,并渲染到預覽區域。
編輯器大致分為頭部菜單欄、左側內容輸入區域、右側預覽區域三個部分。
頭部菜單主要為定自定義標題區域和菜單按鈕,菜單按鈕可通過配置文件進行顯示和隱藏;左側編輯區域,簡單版使用textarea開發,滿足基本需求,
專業版使用codemirror開發,編輯區域支持手動輸入文本和通過頭部菜單插入;右側預覽區域可實時預覽輸入文本,并可通過菜單按鈕,進行編輯區域和預覽區域的切換。
安裝方式
使用npm安裝
- 安裝依賴
npm i -S vue-meditor
將組件復制到項目內
- 將git倉庫代碼拉到本地
git clone https://github.com/zhaoxuhui1122/vue-markdown.git
- 復制src文件夾下內容至components文件夾下
在項目使用
npm包安裝時
簡單版
import Markdown from 'vue-meditor'
專業版
import { MarkdownPro } from 'vue-meditor'
預覽組件
import { MarkdownPreview } from 'vue-meditor'
復制組件到本地時(推薦)
簡單版
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>
API
編輯器基本屬性
value
- Type:
String/Number
- Default:
''
編輯器輸入的文本,支持通過v-dodel
數據雙向綁定設置編輯器內容和獲取編輯器的值。
width
- Type:
String/Number
- Default:
auto
編輯器的初始化寬度。
height
- Type:
Number
- Default:
600
編輯器的初始化高度。
bordered
- Type:
Boolean
- Default:
true
編輯器是否含有邊框。
toolbars
- Type:
Object
- Default:
參見下表
頭部菜單按鈕,通過設置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 | 清空內容 | 否 |
theme
- Type:
String
- Default:
light
編輯器代碼塊主題,目前支持light
、dark
、oneDark
、gitHub
四種代碼塊風格,可通過自定義theme并修改樣式文件進行主題定制。
自定義theme時,預覽區域的會增加一個為markdown-theme-[theme]
的class
。
autoSave
- Type:
Boolean
- Default:
false
是否開啟自動保存,設置為開啟時可通過綁定on-save
事件獲取編輯器內的值和代碼塊主題。
<Markdown @on-save="handleOnSave"/>
handleOnSave({value, theme}){
console.log(value, theme);
}
interval
- Type:
Number
- Default:
10000
自動保存間隔時間,單位:mm
,默認10000mm,需要autoSave = true
時才有效。
exportFileName
- Type:
String
- Default:
unnamed
導出的md文件名稱,默認unnamed.md。
markedOptions
- Type:
Object
- Default:
{}
marked配置項,可以根據需求自定義。
<Markdown :markedOptions="{baseUrl:'http://***.oss-cn-shanghai.aliyuncs.com/'}"/>
isPreview
- Type:
Boolean
- Default:
false
是否是預覽模式,開啟時可作為一個預覽組件使用,與預覽組件功能一致。
copyCode
- Type:
Boolean
- Default:
true
是否支持復制代碼塊內的內容。
copyBtnText
- Type:
String
- Default:
復制代碼
復制代碼按鈕顯示文字。
預覽組件基本屬性
initialValue
- Type:
String/Number
- Default:
''
預覽組件初始化內容,支持動態更新。
theme
- Type:
String
- Default:
light
代碼塊主題,與編輯器編輯器代碼塊主題一致。
markedOptions
- Type:
Object
- Default:
{}
marked配置項,與編輯器內該配置一致。
copyCode
- Type:
Boolean
- Default:
true
是否支持復制代碼塊內的內容。
copyBtnText
- Type:
String
- Default:
復制代碼
復制代碼按鈕顯示文字。
on-ready
編輯器初始化完成時觸發,返回值為Object
,包含組件本身和insertContent
方法。
on-save
編輯器保存事件,自動保存或者手動保存時觸發,支持ctrl+s
或command+s
觸發保存,返回值類型為Object
,包含當前輸入值value
和選擇的代碼塊主題theme
。
on-paste-image
監聽編輯器粘貼圖片事件,在編輯區域內手動粘貼圖片時觸發,可用于支持粘貼插入圖片文件,返回file
文件,上傳文件后可結合on-ready
事件內返回的insertContent
插入圖片。
on-copy
復制代碼塊內容,觸發時返回當前代碼塊的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(``)
}
}
}
支持流程圖、甘特圖等語法
目前編輯器只支持常見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;
}
})
自定義markdown語法轉換
項目內使用的`index.js均為其默認配置功能,如需要特殊轉換,可重寫其內部的解析方法,即重寫其renderer相關方法
參考文檔。
自動生成文檔目錄
預覽區域和文檔預覽組件暫不支持自動生成目錄,實現自動生成目錄思路目前想到的大致有
- 重寫
renderer.heading
方法,為生成的標題添加id,輸入特定快捷鍵,如[TOC]
時,查找預覽區域內的的所有標題標簽,分析等級關系,生成目錄標簽
icon替換
項目內所有的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體積優化
codemirror主要分為主文件、mode相關文件和樣式文件,主文件體積異常的大,mode文件目前只選用了css/jsvascript/markdown/meta/xml五個文件,
其中markdown.js和meta.js為必須引用的,項目中已將常見的編程語言代碼風格定義為css/js/xml之一,例如less/sass/scss按照css規則解析,html/vue按照xml規則解析。
優化可從一下方面入手
- 減少codemirror主文件體積
- 減少引用的mode依賴
highlight.js體積優化
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;
專業版編輯器codemirror/simple.js
優化思路:無
iconfont 體積優化
只需要preview組件時,避免引入所有icon,參考功能擴展里icon替換方法。
升級路線
- 普通版編輯器對選中文本進行操作功能
- 文檔目錄功能
- 優化專業版編輯器體積
- react版開發
- ...
問題反饋
對于功能上的缺陷、使用方法和希望擴展的功能,可以提 Issues。