vue-markdown編輯器

簡介

一款使用marked和highlight.js開發的一款markdown編輯器,除常見markdown語法外,支持快捷輸入、圖片粘貼、代碼復制、全屏編輯、預覽等功能。

使用起來簡單方便,只需幾行代碼,即可在你的頁面上引入一個markdown編輯器,編輯區支持像專業編輯器那樣。

編輯器涵蓋了常用的markdown編輯器功能,可通過已有屬性進行配置,對編輯器功能和樣式進行基本的配置,也可根據需求進行深度定制。

項目地址

文檔地址

示例

image.png

特點

  • 使用簡單,只需要安裝npm包,引入項目即可使用,不需要繁瑣的初始化配置。
  • 方便擴展,根據實際需求,支持常見的功能配置,也可根據實際需求進行深度定制。
  • 體積小,加載速度快,npm包刪除了highlight.js和codemirror里的依賴。
  • 靈活的主題,默認支持四種代碼塊風格,也可根據實際需求定制自己的主題樣式
  • 功能強大,支持專業版的編輯器,使用codemirror實現編輯窗口,可識別markdown語法
  • 鍵盤事件監聽,如保存、粘貼、回車時上次輸入語法判斷等
  • 可擴展性強,除了提供的屬性配置編輯器,也可直接在原有組件基礎上進行二次開發

實現思路

通過監聽文本輸入區域內內容的變化,實時將輸入的markdown語法進行編譯,并渲染到預覽區域。

編輯器大致分為頭部菜單欄、左側內容輸入區域、右側預覽區域三個部分。
頭部菜單主要為定自定義標題區域和菜單按鈕,菜單按鈕可通過配置文件進行顯示和隱藏;左側編輯區域,簡單版使用textarea開發,滿足基本需求,
專業版使用codemirror開發,編輯區域支持手動輸入文本和通過頭部菜單插入;右側預覽區域可實時預覽輸入文本,并可通過菜單按鈕,進行編輯區域和預覽區域的切換。

安裝方式

使用npm安裝

  1. 安裝依賴
npm i -S vue-meditor

將組件復制到項目內

  1. 將git倉庫代碼拉到本地
git clone https://github.com/zhaoxuhui1122/vue-markdown.git
  1. 復制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 分屏模式切換
print 打印
theme 主題切換
fullscreen 全屏
exportmd 導出為*.md文件
importmd 導入本地*.md文件
save 保存按鈕
clear 清空內容

theme

  • Type: String
  • Default: light

編輯器代碼塊主題,目前支持lightdarkoneDarkgitHub四種代碼塊風格,可通過自定義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+scommand+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(`![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;
    }
})

自定義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.jsmarkediconfont、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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,278評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,241評論 2 375

推薦閱讀更多精彩內容