vue-markdown編輯器

簡(jiǎn)介

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

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

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

項(xiàng)目地址

文檔地址

示例

image.png

特點(diǎn)

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

實(shí)現(xiàn)思路

通過監(jiān)聽文本輸入?yún)^(qū)域內(nèi)內(nèi)容的變化,實(shí)時(shí)將輸入的markdown語法進(jìn)行編譯,并渲染到預(yù)覽區(qū)域。

編輯器大致分為頭部菜單欄、左側(cè)內(nèi)容輸入?yún)^(qū)域、右側(cè)預(yù)覽區(qū)域三個(gè)部分。
頭部菜單主要為定自定義標(biāo)題區(qū)域和菜單按鈕,菜單按鈕可通過配置文件進(jìn)行顯示和隱藏;左側(cè)編輯區(qū)域,簡(jiǎn)單版使用textarea開發(fā),滿足基本需求,
專業(yè)版使用codemirror開發(fā),編輯區(qū)域支持手動(dòng)輸入文本和通過頭部菜單插入;右側(cè)預(yù)覽區(qū)域可實(shí)時(shí)預(yù)覽輸入文本,并可通過菜單按鈕,進(jìn)行編輯區(qū)域和預(yù)覽區(qū)域的切換。

安裝方式

使用npm安裝

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

將組件復(fù)制到項(xiàng)目?jī)?nèi)

  1. 將git倉(cāng)庫代碼拉到本地
git clone https://github.com/zhaoxuhui1122/vue-markdown.git
  1. 復(fù)制src文件夾下內(nèi)容至components文件夾下

在項(xiàng)目使用

npm包安裝時(shí)

簡(jiǎn)單版

import Markdown from 'vue-meditor'

專業(yè)版

import { MarkdownPro } from 'vue-meditor'

預(yù)覽組件

import { MarkdownPreview } from 'vue-meditor'

復(fù)制組件到本地時(shí)(推薦)

簡(jiǎn)單版

import Markdown from '@/components/markdown/...';

專業(yè)版

import MarkdownPro from '@/components/markdown/pro';

預(yù)覽組件

import MarkdownPreview from '@/components/markdown/preview';

在頁面內(nèi)使用

<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數(shù)據(jù)雙向綁定設(shè)置編輯器內(nèi)容和獲取編輯器的值。

width

  • Type: String/Number
  • Default: auto

編輯器的初始化寬度。

height

  • Type: Number
  • Default: 600

編輯器的初始化高度。

bordered

  • Type: Boolean
  • Default: true

編輯器是否含有邊框。

toolbars

  • Type: Object
  • Default: 參見下表

頭部菜單按鈕,通過設(shè)置true or false控制決定是否顯示,目前配置支持持控制按鈕顯示隱藏,后續(xù)將支持根據(jù)配置顯示排列順序。

名稱 說明 默認(rèn)是否顯示
strong 粗體
italic 斜體
overline 刪除線
h1 標(biāo)題1
h2 標(biāo)題2
h3 標(biāo)題3
h4 標(biāo)題4
h5 標(biāo)題5
h6 標(biāo)題6
hr 分割線
quote 引用
ul 無序列表
ol 有序列表
code 代碼塊
link 鏈接
image image
table 表格
checked 已完成列表
notChecked 未完成列表
preview 預(yù)覽
split 分屏模式切換
print 打印
theme 主題切換
fullscreen 全屏
exportmd 導(dǎo)出為*.md文件
importmd 導(dǎo)入本地*.md文件
save 保存按鈕
clear 清空內(nèi)容

theme

  • Type: String
  • Default: light

編輯器代碼塊主題,目前支持lightdarkoneDark、gitHub四種代碼塊風(fēng)格,可通過自定義theme并修改樣式文件進(jìn)行主題定制。

自定義theme時(shí),預(yù)覽區(qū)域的會(huì)增加一個(gè)為markdown-theme-[theme]class

autoSave

  • Type: Boolean
  • Default: false

是否開啟自動(dòng)保存,設(shè)置為開啟時(shí)可通過綁定on-save事件獲取編輯器內(nèi)的值和代碼塊主題。

<Markdown @on-save="handleOnSave"/>
 handleOnSave({value, theme}){
        console.log(value, theme);
    }

interval

  • Type: Number
  • Default: 10000

自動(dòng)保存間隔時(shí)間,單位:mm,默認(rèn)10000mm,需要autoSave = true時(shí)才有效。

exportFileName

  • Type: String
  • Default: unnamed

導(dǎo)出的md文件名稱,默認(rèn)unnamed.md。

markedOptions

  • Type: Object
  • Default: {}

marked配置項(xiàng),可以根據(jù)需求自定義。

<Markdown :markedOptions="{baseUrl:'http://***.oss-cn-shanghai.aliyuncs.com/'}"/>

isPreview

  • Type: Boolean
  • Default: false

是否是預(yù)覽模式,開啟時(shí)可作為一個(gè)預(yù)覽組件使用,與預(yù)覽組件功能一致。

copyCode

  • Type: Boolean
  • Default: true

是否支持復(fù)制代碼塊內(nèi)的內(nèi)容。

copyBtnText

  • Type: String
  • Default: 復(fù)制代碼

復(fù)制代碼按鈕顯示文字。

預(yù)覽組件基本屬性

initialValue

  • Type: String/Number
  • Default: ''

預(yù)覽組件初始化內(nèi)容,支持動(dòng)態(tài)更新。

theme

  • Type: String
  • Default: light

代碼塊主題,與編輯器編輯器代碼塊主題一致。

markedOptions

  • Type: Object
  • Default: {}

marked配置項(xiàng),與編輯器內(nèi)該配置一致。

copyCode

  • Type: Boolean
  • Default: true

是否支持復(fù)制代碼塊內(nèi)的內(nèi)容。

copyBtnText

  • Type: String
  • Default: 復(fù)制代碼

復(fù)制代碼按鈕顯示文字。

on-ready

編輯器初始化完成時(shí)觸發(fā),返回值為Object,包含組件本身和insertContent方法。

on-save

編輯器保存事件,自動(dòng)保存或者手動(dòng)保存時(shí)觸發(fā),支持ctrl+scommand+s觸發(fā)保存,返回值類型為Object,包含當(dāng)前輸入值value和選擇的代碼塊主題theme。

on-paste-image

監(jiān)聽編輯器粘貼圖片事件,在編輯區(qū)域內(nèi)手動(dòng)粘貼圖片時(shí)觸發(fā),可用于支持粘貼插入圖片文件,返回file文件,上傳文件后可結(jié)合on-ready事件內(nèi)返回的insertContent插入圖片。

on-copy

復(fù)制代碼塊內(nèi)容,觸發(fā)時(shí)返回當(dāng)前代碼塊的text,copyCode開啟時(shí)才有效。

二次開發(fā)

粘貼插入圖片

on-paste-image雖然可以支持圖片粘貼事件的監(jiān)聽,但不會(huì)處理圖片上傳至服務(wù)器并將鏈接插入編輯器這段邏輯。

目前如果想要支持粘貼插入圖片,需要在on-paste-image方法里上傳圖片文件,拿到圖片地址后,使用on-ready方法里返回的insertContent方法插入圖片。

上述操作顯得過于復(fù)雜,可以直接在源碼里擴(kuò)展mixins里的handlePaste方法,圖片上傳完成后,直接調(diào)用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語法,如果需要實(shí)現(xiàn)如流程圖等功能,需要進(jìn)一步擴(kuò)展,以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的流程圖為例,具體實(shí)現(xiàn)思路如下:

默認(rèn)情況下,markedjs會(huì)使用renderer.code方法對(duì)輸入的代碼塊進(jìn)行解析,并會(huì)借助highlight.js支持語法高亮。
可以將流程圖語法輸入到代碼塊內(nèi),并標(biāo)明語言,重寫marked.Renderer的code解析方法,結(jié)合結(jié)合flowchart.js路程圖代碼進(jìn)行解析,返回文本內(nèi)容。

修改`/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, {/*相關(guān)配置*/});
        return  dom.innerHTML;
    } else {// 默認(rèn)解析
        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語法轉(zhuǎn)換

項(xiàng)目?jī)?nèi)使用的`index.js均為其默認(rèn)配置功能,如需要特殊轉(zhuǎn)換,可重寫其內(nèi)部的解析方法,即重寫其renderer相關(guān)方法
參考文檔。

自動(dòng)生成文檔目錄

預(yù)覽區(qū)域和文檔預(yù)覽組件暫不支持自動(dòng)生成目錄,實(shí)現(xiàn)自動(dòng)生成目錄思路目前想到的大致有

  • 重寫renderer.heading 方法,為生成的標(biāo)題添加id,輸入特定快捷鍵,如[TOC]時(shí),查找預(yù)覽區(qū)域內(nèi)的的所有標(biāo)題標(biāo)簽,分析等級(jí)關(guān)系,生成目錄標(biāo)簽

icon替換

項(xiàng)目?jī)?nèi)所有的icon和命名參考/assets/font/index.html,替換時(shí)需注意,預(yù)覽區(qū)域的checkbox為icon,注意一并替換,
修改/assets/css/index.less內(nèi)的input[type="checkbox"]:after樣式。

代碼體積優(yōu)化

公共代碼提取

npm包構(gòu)建時(shí),三個(gè)組件完全獨(dú)立,沒有抽離公共文件,所以,當(dāng)同一個(gè)項(xiàng)目?jī)?nèi)引入其中的兩個(gè)或三個(gè)組件都引入時(shí),存在一定的重復(fù)代碼,
主要為highlight.jsmarked、iconfont、css樣式幾個(gè)部分。

解決方式:將組件復(fù)制到本地項(xiàng)目,打包時(shí)將這些文件作為公共文件抽離出來。

注意:三個(gè)組件中使用的iconfont為同一套,如果只是單純的使用preview組件,
將會(huì)引入整個(gè)項(xiàng)目所使用的iconfont,可刪除iconfont的引入,
重寫input[type="checkbox"]的樣式,preview組件體積將會(huì)減少一半,樣式文件位于markdown/assets/css/index.less。

codemirror體積優(yōu)化

codemirror主要分為主文件、mode相關(guān)文件和樣式文件,主文件體積異常的大,mode文件目前只選用了css/jsvascript/markdown/meta/xml五個(gè)文件,
其中markdown.js和meta.js為必須引用的,項(xiàng)目中已將常見的編程語言代碼風(fēng)格定義為css/js/xml之一,例如less/sass/scss按照css規(guī)則解析,html/vue按照xml規(guī)則解析。
優(yōu)化可從一下方面入手

  • 減少codemirror主文件體積
  • 減少引用的mode依賴

highlight.js體積優(yōu)化

highlight.js原本體積也是較大的,主要原因?yàn)?,編譯時(shí)為支持各種代碼語言,引入了相應(yīng)的解析文件,
項(xiàng)目?jī)?nèi)已根據(jù)常見的代碼語言進(jìn)行了一次篩選,進(jìn)行按需引入,可根據(jù)自身需求,再次對(duì)引用文件進(jìn)行刪減

參見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;

專業(yè)版編輯器codemirror/simple.js

優(yōu)化思路:無

iconfont 體積優(yōu)化

只需要preview組件時(shí),避免引入所有icon,參考功能擴(kuò)展里icon替換方法。

升級(jí)路線

  • 普通版編輯器對(duì)選中文本進(jìn)行操作功能
  • 文檔目錄功能
  • 優(yōu)化專業(yè)版編輯器體積
  • react版開發(fā)
  • ...

問題反饋

對(duì)于功能上的缺陷、使用方法和希望擴(kuò)展的功能,可以提 Issues。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容