Vditor 一款瀏覽器端的 Markdown 編輯器,支持所見即所得(富文本)、即時渲染(類似 Typora)和分屏預覽模式

Vditor
易于使用的 Markdown 編輯器,為適配不同的應用場景而生

npm bundle size

English | Demo

? 簡介

Vditor 是一款瀏覽器端的 Markdown 編輯器,支持所見即所得、即時渲染(類似 Typora)和分屏預覽模式。它使用 TypeScript 實現,支持原生 JavaScript、Vue、React、Angular,提供桌面版。

歡迎到 Vditor 官方討論區了解更多。同時也歡迎關注 B3log 開源社區微信公眾號 B3log開源

?️ 背景

隨著 Markdown 排版方式的普及,越來越多的應用開始集成 Markdown 編輯器。目前主流可集成的 Markdown 編輯器現狀如下:

  • 有的僅支持分屏預覽,即編輯區和預覽區分離
  • 有的同時支持所見即所得和分屏預覽,但所見即所得模式下不能完整支持 Markdown 語法排版
  • 幾乎沒有類似 Typora 的即時渲染

而這三點恰好對應了三種應用場景:

  • 分屏預覽:適配傳統的 Markdown 使用場景,適合大屏下編輯排版
  • 所見即所得:對不熟悉 Markdown 的用戶友好,熟悉 Markdown 的用戶也可以無縫使用
  • 即時渲染:理論上這是最為優雅的 Markdown 編輯方式,讓熟悉 Markdown 的用戶能夠更專注于內容創作

所以,一個能夠適配應用場景的 Markdown 編輯器至關重要,它需要考慮到:

  • 傳統 Markdown 用戶的使用場景,提供分屏預覽
  • 富文本編輯用戶的使用場景,提供所見即所得
  • 高階 Markdown 用戶的使用場景,提供即時渲染

Vditor 在這些方面做了努力,希望能為現代化的通用 Markdown 編輯領域做出一些貢獻。

✨ 特性

  • 支持三種編輯模式:所見即所得(wysiwyg)、即時渲染(ir)、分屏預覽(sv)
  • 支持大綱、數學公式、腦圖、圖表、流程圖、甘特圖、時序圖、五線譜、多媒體、語音閱讀、標題錨點、代碼高亮及復制、graphviz 渲染
  • 內置安全過濾、導出、圖片懶加載、任務列表、多平臺預覽、多主題切換、復制到微信公眾號/知乎功能
  • 實現 CommonMark 和 GFM 規范,可對 Markdown 進行格式化和語法樹查看,并支持 10+ 項配置
  • 工具欄包含 36+ 項操作,除支持擴展外還可對每一項中的快捷鍵、提示、提示位置、圖標、點擊事件、類名、子工具欄進行自定義
  • 表情/at/話題等自動補全擴展
  • 可使用拖拽、剪切板粘貼上傳,顯示實時上傳進度,支持 CORS 跨域上傳
  • 實時保存內容,防止意外丟失
  • 錄音支持,用戶可直接發布語音
  • 粘貼 HTML 自動轉換為 Markdown,如粘貼中包含外鏈圖片可通過指定接口上傳到服務器
  • 支持主窗口大小拖拽、字符計數
  • 多主題支持,內置黑白綠三套主題
  • 多語言支持,內置中、英、韓文本地化
  • 支持主流瀏覽器,對移動端友好

? 編輯模式

所見即所得(WYSIWYG)

所見即所得模式對不熟悉 Markdown 的用戶較為友好,熟悉 Markdown 的話也可以無縫使用。

即時渲染(IR)

即時渲染模式對熟悉 Typora 的用戶應該不會感到陌生,理論上這是最優雅的 Markdown 編輯方式。

分屏預覽(SV)

傳統的分屏預覽模式適合大屏下的 Markdown 編輯。

? 語法支持

  • 所有 CommonMark 語法:分隔線、ATX 標題、Setext 標題、縮進代碼塊、圍欄代碼塊、HTML 塊、鏈接引用定義、段落、塊引用、列表、反斜杠轉義、HTML 實體、行級代碼、強調、加粗、鏈接、圖片、行級 HTML、硬換行、軟換行和純文本。
  • 所有 GFM 語法:表格、任務列表項、刪除線、自動鏈接、XSS 過濾
  • 常用 Markdown 擴展語法:腳注、ToC、自定義標題 ID
  • 圖表語法
    • 流程圖、時序圖、甘特圖,通過 Mermaid 支持
    • Graphviz
    • 折線圖、餅圖、腦圖等,通過 ECharts 支持
  • 五線譜:通過 abc.js 支持
  • 數學公式:數學公式塊、行級數學公式,通過 MathJax 和 KaTeX 支持
  • YAML Front Matter
  • 中文語境優化
    • 中西文之間插入空格
    • 術語拼寫修正
    • 中文后跟英文逗號句號等標點替換為中文對應標點

以上大部分特性可以通過開關配置是否啟用,開發者可根據自己的應用場景選擇搭配。

? 案例

  • Sym 一款用 Java 實現的現代化社區(論壇/BBS/社交網路/部落格)平臺
  • Solo & Pipe B3log 分布式社區的部落格端節點,歡迎加入下一代社區網路
  • 思源筆記 一款 Markdown 塊級引用和雙向鏈接的網狀筆記應用
  • Arya 基于 Vue、Vditor,所構建的在線 Markdown 編輯器
  • 更多案例

?️ 使用文檔

CommonJS

  • 安裝依賴
npm install vditor --save
  • 在代碼中引入并初始化對象,可參考 index.js
import Vditor from 'vditor'
import "~vditor/src/assets/scss/index"

const vditor = new Vditor(id, {options...})

HTML script

  • 在 HTML 中插入 CSS 和 JavaScript,可參考 demo
<!-- ⚠️生產環境請指定版本號,如 https://cdn.jsdelivr.net/npm/[email protected]/dist... -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vditor/dist/index.css" />
<script src="https://cdn.jsdelivr.net/npm/vditor/dist/index.min.js" defer></script>

示例代碼

  • 官方示例 / 示例源碼
  • CommonJS Editor
  • CommonJS Render

主題

編輯器主題

編輯器所展現的外觀。內置 classic,dark 2 套主題。

  • 編輯器初始化時可通過 options.theme 設置內置主題
  • 初始化完成后可通過 setTheme 更新編輯器主題
  • 可通過修改 index.scss 中的變量對主題顏色進行定制
  • 可參考現有結構和類名在原有基礎上進行修改

內容主題

Markdown 輸出的 HTML 所展現的外觀。內置 light,dark,wechat 3 套主題。支持內容主題擴展接口。

  • 需在顯示元素上添加 class="vditor-reset"
  • 編輯器初始化時可通過 options.preview.theme 設置內置或自己開發的主題列表
  • 內容渲染初始化時可通過 IPreviewOptions.theme 設置內置或自己開發的主題
  • 初始化完成后可通過 setThemesetContentTheme 更新內容主題

代碼主題

代碼塊所展現的外觀。內置 GitHub 等 36 套主題。

  • 編輯器初始化時可通過 options.preview.hljs 對代碼塊樣式、行號、是否啟用進行設置
  • 內容渲染初始化時可通過 IPreviewOptions.hljs 對代碼塊樣式、行號、是否啟用進行設置
  • 初始化完成后可通過 setThemesetCodeTheme 更新代碼主題

API

id

可填入元素 id 或元素自身 HTMLElement

⚠️:當填入元素自身的 HTMLElement 時需設置 options.cache.id 或將 options.cache.enable 設置為 false

options

說明 默認值
after 編輯器異步渲染完成后的回調方法
height 編輯器總高度 ‘auto’
minHeight 編輯區域最小高度
width 編輯器總寬度,支持 % ‘auto’
placeholder 輸入區域為空時的提示
lang 多語言:en_US, ja_JP, ko_KR, zh_CN ‘zh_CN’
input(value: string, previewElement?: HTMLElement) 輸入后觸發
focus(value: string) 聚焦后觸發
blur(value: string) 失焦后觸發
esc(value: string) esc 按下后觸發
ctrlEnter(value: string) ⌘/ctrl+enter 按下后觸發
select(value: string) 編輯器中選中文字后觸發
tab tab 鍵操作字符串,支持 \t 及任意字符串
typewriterMode 是否啟用打字機模式 false
cdn 配置自建 CDN 地址 https://cdn.jsdelivr.net/npm/vditor@${VDITOR_VERSION}
mode 可選模式:sv, ir, wysiwyg ‘ir’
debugger 是否顯示日志 false
value 編輯器初始化值
theme 主題:classic, dark ‘classic’
icon 圖標風格:ant, material ‘ant’
outline 是否展現大綱 false

options.toolbar

  • 工具欄,可使用 name 進行簡寫: toolbar: ['emoji', 'br', 'bold', '|', 'line'] 。默認值參見 src/ts/util/Options.ts
  • name 可枚舉為: emoji , headings , bold , italic , strike , | , line , quote , list , ordered-list , check ,outdent ,indent , code , inline-code , insert-after , insert-before ,undo , redo , upload , link , table , record , edit-mode , both , preview , fullscreen , outline , code-theme , content-theme , export, devtools , info , help , br
  • name 不在枚舉中時,可以添加自定義按鈕,格式如下:

new Vditor('vditor', {
  toolbar: [
    {
      hotkey: '⌘-⇧-S',
      name: 'sponsor',
      tipPosition: 's',
      tip: '成為贊助者',
      className: 'right',
      icon: '<svg t="1589994565028" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2808" width="32" height="32"><path d="M506.6 423.6m-29.8 0a29.8 29.8 0 1 0 59.6 0 29.8 29.8 0 1 0-59.6 0Z" fill="#0F0F0F" p-id="2809"></path><path d="M717.8 114.5c-83.5 0-158.4 65.4-211.2 122-52.7-56.6-127.7-122-211.2-122-159.5 0-273.9 129.3-273.9 288.9C21.5 562.9 429.3 913 506.6 913s485.1-350.1 485.1-509.7c0.1-159.5-114.4-288.8-273.9-288.8z" fill="#FAFCFB" p-id="2810"></path><path d="M506.6 926c-22 0-61-20.1-116-59.6-51.5-37-109.9-86.4-164.6-139-65.4-63-217.5-220.6-217.5-324 0-81.4 28.6-157.1 80.6-213.1 53.2-57.2 126.4-88.8 206.3-88.8 40 0 81.8 14.1 124.2 41.9 28.1 18.4 56.6 42.8 86.9 74.2 30.3-31.5 58.9-55.8 86.9-74.2 42.5-27.8 84.3-41.9 124.2-41.9 79.9 0 153.2 31.5 206.3 88.8 52 56 80.6 131.7 80.6 213.1 0 103.4-152.1 261-217.5 324-54.6 52.6-113.1 102-164.6 139-54.8 39.5-93.8 59.6-115.8 59.6zM295.4 127.5c-72.6 0-139.1 28.6-187.3 80.4-47.5 51.2-73.7 120.6-73.7 195.4 0 64.8 78.3 178.9 209.6 305.3 53.8 51.8 111.2 100.3 161.7 136.6 56.1 40.4 88.9 54.8 100.9 54.8s44.7-14.4 100.9-54.8c50.5-36.3 108-84.9 161.7-136.6 131.2-126.4 209.6-240.5 209.6-305.3 0-74.9-26.2-144.2-73.7-195.4-48.2-51.9-114.7-80.4-187.3-80.4-61.8 0-127.8 38.5-201.7 117.9-2.5 2.6-5.9 4.1-9.5 4.1s-7.1-1.5-9.5-4.1C423.2 166 357.2 127.5 295.4 127.5z" fill="#141414" p-id="2811"></path><path d="M353.9 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2812"></path><path d="M659.3 415.6m-33.8 0a33.8 33.8 0 1 0 67.6 0 33.8 33.8 0 1 0-67.6 0Z" fill="#0F0F0F" p-id="2813"></path><path d="M411.6 538.5c0 52.3 42.8 95 95 95 52.3 0 95-42.8 95-95v-31.7h-190v31.7z" fill="#5B5143" p-id="2814"></path><path d="M506.6 646.5c-59.6 0-108-48.5-108-108v-31.7c0-7.2 5.8-13 13-13h190.1c7.2 0 13 5.8 13 13v31.7c0 59.5-48.5 108-108.1 108z m-82-126.7v18.7c0 45.2 36.8 82 82 82s82-36.8 82-82v-18.7h-164z" fill="#141414" p-id="2815"></path><path d="M450.4 578.9a54.7 27.5 0 1 0 109.4 0 54.7 27.5 0 1 0-109.4 0Z" fill="#EA64F9" p-id="2816"></path><path d="M256 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2817"></path><path d="M703.3 502.7a32.1 27.5 0 1 0 64.2 0 32.1 27.5 0 1 0-64.2 0Z" fill="#EFAFF9" p-id="2818"></path></svg>',
      click () {alert('捐贈地址:https://ld246.com/sponsor')},
    }],
})
說明 默認值
name 唯一標示
icon svg 圖標
tip 提示
tipPosition 提示位置:ne, nw
hotkey 快捷鍵,格式為⌘/ctrl-key⌘/ctrl-⇧/shift-key
suffix 插入編輯器中的后綴
prefix 插入編輯器中的前綴
click() 自定義按鈕點擊時觸發的事件
className 樣式名
toolbar?: Array<options.toolbar> 子菜單

options.toolbarConfig

說明 默認值
hide 是否隱藏工具欄 false
pin 是否固定工具欄 false

options.counter

說明 默認值
enable 是否啟用計數器 false
max 允許輸入的最大值
type 統計類型:md,text ‘md’

options.cache

說明 默認值
enable 是否使用 localStorage 進行緩存 true
id 緩存 key,第一個參數為元素且啟用緩存時必填
after(html: string): string 緩存后的回調

options.comment

⚠️:僅支持 wysiwyg 模式

說明 默認值
enable 是否啟用評論模式 false
add(id: string, text: string, commentsData: ICommentsData[]) 添加評論回調
remove(ids: string[]) 刪除評論回調
scroll(top: number) 滾動回調
adjustTop(commentsData: ICommentsData[]) 文檔修改時,適配評論高度

options.preview

說明 默認值
delay 預覽 debounce 毫秒間隔 1000
maxWidth 預覽區域最大寬度 800
mode 顯示模式:both, editor ‘both’
url md 解析請求
parse(element: HTMLElement) 預覽回調
transform(html: string): string 渲染之前回調

options.preview.hljs

說明 默認值
enable 是否啟用代碼高亮 true
style 可選值參見 Chroma github
lineNumber 是否啟用行號 false

options.preview.markdown

說明 默認值
autoSpace 自動空格 false
fixTermTypo 自動矯正術語 false
chinesePunct 自動矯正標點 false
toc 插入目錄 false
footnotes 腳注 true
codeBlockPreview wysiwyg 和 ir 模式下是否對代碼塊進行渲染 true
mathBlockPreview wysiwyg 和 ir 模式下是否對數學公式進行渲染 true
paragraphBeginningSpace 段落開頭空兩個 false
sanitize 是否啟用過濾 XSS true
listStyle 為列表添加 data-style 屬性 false
linkBase 鏈接相對路徑前綴
linkPrefix 鏈接強制前綴
mark 啟用 mark 標記 false

options.preview.theme

說明 默認值
current 當前主題 “light”
list 可選主題列表 { dark: “Dark”, light: “Light”, wechat: “WeChat” }
path 主題樣式地址 https://cdn.jsdelivr.net/npm/vditor@${VDITOR_VERSION}/dist/css/content-theme

options.preview.math

說明 默認值
inlineDigit 內聯數學公式起始 $ 后是否允許數字 false
macros 使用 MathJax 渲染時傳入的宏定義 {}
engine 數學公式渲染引擎:KaTeX, MathJax ‘KaTeX’

options.preview.actions?: Array<IPreviewAction | IPreviewActionCustom>

默認值為 [“desktop”, “tablet”, “mobile”, “mp-wechat”, “zhihu”]。
可從默認值中挑選進行配置,也可使用以下字段進行自定制開發。

說明 默認值
key 按鈕唯一標識,不能為空
text 按鈕文字
tooltip 提示
className 按鈕類名
click(key: string) 按鈕點擊回調事件

options.hint

說明 默認值
delay 提示 debounce 毫秒間隔 200
emoji 默認表情,可從 lute/emoji_map 中選取,也可自定義 { ‘+1’: ‘?’, ‘-1’: ‘?’, ‘heart’: ‘❤️’, ‘cold_sweat’: ‘?’ }
emojiTail 常用表情提示
emojiPath 表情圖片地址 https://cdn.jsdelivr.net/npm/vditor@${VDITOR_VERSION}/dist/images/emoji
extend: IHintExtend[] 對 @/話題等關鍵字自動補全的擴展 []
interface IHintExtend {
    key: string;

    hint?(value: string): Array<{
        html: string;
        value: string;
    }>;
}

options.upload

  • 文件上傳的數據結構如下。后端返回的數據結構不一致時,可使用 format 進行轉換。
// POST data  
xhr.send(formData);  // formData = FormData.append("file[]", File)  
// return data  
{  
 "msg": "",  
 "code": 0,  
 "data": {  
 "errFiles": ['filename', 'filename2'],  
 "succMap": {  
   "filename3": "filepath3",  
   "filename3": "filepath3"  
   }  
 }  
}
  • 為了防止站外圖片失效, linkToImgUrl 可將剪貼板中的站外圖片地址傳到服務器端進行保存處理,其數據結構如下:
// POST data  
xhr.send(JSON.stringify({url: src})); // src 為站外圖片地址  
// return data  
{  
 msg: '',  
 code: 0,  
 data : {  
   originalURL: '',  
   url: ''  
 }  
}
  • successformaterror 不會同時觸發,具體調用情況如下:
if (xhr.status === 200) {
    if (vditor.options.upload.success) {
        vditor.options.upload.success(editorElement, xhr.responseText);
    } else {
        let responseText = xhr.responseText;
        if (vditor.options.upload.format) {
            responseText = vditor.options.upload.format(files as File [], xhr.responseText);
        }
        genUploadedLabel(responseText, vditor);
    }
} else {
    if (vditor.options.upload.error) {
        vditor.options.upload.error(xhr.responseText);
    } else {
        vditor.tip.show(xhr.responseText);
    }
}
說明 默認值
url 上傳 url
max 上傳文件最大 Byte 10 * 1024 * 1024
linkToImgUrl 剪切板中包含圖片地址時,使用此 url 重新上傳
linkToImgCallback(responseText: string) 圖片地址上傳回調
linkToImgFormat(responseText: string): string 對圖片地址上傳的返回值進行格式化
success(editor: HTMLPreElement, msg: string) 上傳成功回調
error(msg: string) 上傳失敗回調
token CORS 上傳驗證,頭為 X-Upload-Token
withCredentials 跨站點訪問控制 false
headers 請求頭設置
filename(name: string): string 文件名安全處理 name => name.replace(/\W/g, ”)
accept 文件上傳類型,同 input accept
validate(files: File[]) => string | boolean 校驗,成功時返回 true 否則返回錯誤資訊
handler(files: File[]) => string | null 自定義上傳,當發生錯誤時返回錯誤資訊
format(files: File[], responseText: string): string 對服務端返回的數據進行轉換,以滿足內置的數據結構
file(files: File[]): File[] 將上傳的文件處理后再返回
setHeaders(): { [key: string]: string } 上傳前使用返回值設置頭
extraData: { [key: string]: string | Blob } 為 FormData 添加額外的參數
multiple 上傳文件是否為多個 true
fieldName 上傳字段名稱 ‘file[]’

options.resize

說明 默認值
enable 是否支持大小拖拽 false
position 拖拽欄位置:top, bottom ‘bottom’
after(height: number) 拖拽結束的回調

options.classes

說明 默認值
preview 預覽元素上的 className

methods

說明
getValue() 獲取 Markdown 內容
getHTML() 獲取 HTML 內容
insertValue(value: string, render = true) 在焦點處插入內容,并默認進行 Markdown 渲染
focus() 聚焦到編輯器
blur() 讓編輯器失焦
disabled() 禁用編輯器
enable() 解除編輯器禁用
getSelection(): string 返回選中的字符串
setValue(markdown: string, clearStack = false) 設置編輯器內容且選中清空歷史棧
clearStack() 清空撤銷和重做記錄棧
renderPreview(value?: string) 設置預覽區域內容
getCursorPosition():{top: number, left: number} 獲取焦點位置
deleteValue() 刪除選中內容
updateValue(value: string) 更新選中內容
isUploading() 上傳是否還在進行中
clearCache() 清除緩存
disabledCache() 禁用緩存
enableCache() 啟用緩存
html2md(value: string) HTML 轉 md
tip(text: string, time: number) 消息提示。time 為 0 將一直顯示
setPreviewMode(mode: “both” | “editor”) 設置預覽模式
setTheme(theme: “dark” | “classic”, contentTheme?: string, codeTheme?: string, contentThemePath?: string) 設置主題、內容主題及代碼塊風格
getCurrentMode(): string 獲取編輯器當前編輯模式
destroy() 銷毀編輯器
getCommentIds(): {id: string, top: number}[] 獲取所有評論
hlCommentIds(ids: string[]) 高亮評論
unHlCommentIds(ids: string[]) 取消評論高亮
removeCommentIds(removeIds: string[]) 刪除評論

static methods

  • 不需要進行編輯操作時,僅需引入 method.min.js 后如下直接調用
Vditor.mermaidRender(document)

import VditorPreview from 'vditor/dist/method.min'  
VditorPreview.mermaidRender(document)
  • 需要對頁面中的 Markdown 進行渲染時可直接調用 preview 方法,參數如下:
previewElement: HTMLDivElement,   // 使用該元素進行渲染
markdown: string,  // 需要渲染的 markdown 原文
options?: IPreviewOptions {  
 anchor?: number;  // 為標題添加錨點 0:不渲染;1:渲染于標題前;2:渲染于標題后,默認 0
 customEmoji?: { [key: string]: string };    // 自定義 emoji,默認為 {}  
 lang?: (keyof II18nLang);    // 語言,默認為 'zh_CN'  
 emojiPath?: string;    // 表情圖片路徑 
 hljs?: IHljs; // 參見 options.preview.hljs 
 speech?: {  // 對選中后的內容進行閱讀
  enable?: boolean,
 };
 math?: IMath; // 數學公式渲染配置
 cdn?: string; // 自建 CDN 地址
 transform?(html: string): string; // 在渲染前進行的回調方法
 after?(); // 渲染完成后的回調
 lazyLoadImage?: string; // 設置為 Loading 圖片地址后將啟用圖片的懶加載
 markdown?: options.preview.markdown;
 theme?: options.preview.theme;
 renderers?: ILuteRender; // 自定義渲染 https://ld246.com/article/1588412297062
}
  • ⚠️ method.min.jsindex.min.js 不可同時引入
說明
mermaidRender(element: HTMLElement, cdn = options.cdn, theme = options.theme) 流程圖/時序圖/甘特圖
flowchartRender(element: HTMLElement, cdn = options.cdn) flowchart 渲染
codeRender(element: HTMLElement, lang: (keyof II18nLang) = “zh_CN”) 為 element 中的代碼塊添加復制按鈕
chartRender(element: (HTMLElement | Document) = document, cdn = options.cdn, theme = options.theme) 圖表渲染
mindmapRender(element: (HTMLElement | Document) = document, cdn = options.cdn, theme = options.theme) 腦圖渲染
abcRender(element: (HTMLElement | Document) = document, cdn = options.cdn) 五線譜渲染
md2html(mdText: string, options?: IPreviewOptions): Promise<string> Markdown 文本轉換為 HTML,該方法需使用異步編程
preview(previewElement: HTMLDivElement, markdown: string, options?: IPreviewOptions) 頁面 Markdown 文章渲染
highlightRender(hljsOption?: IHljs, element?: HTMLElement | Document, cdn = options.cdn) 為 element 中的代碼塊進行高亮渲染
mediaRender(element: HTMLElement) 為特定鏈接分別渲染為視訊、音頻、嵌入的 iframe
mathRender(element: HTMLElement, options?: {cdn?: string, math?: IMath}) 對數學公式進行渲染
speechRender(element: HTMLElement, lang?: (keyof II18nLang)) 對選中的文字進行閱讀
graphvizRender(element: HTMLElement, cdn?: string) 對 graphviz 進行渲染
outlineRender(contentElement: HTMLElement, targetElement: Element) 對大綱進行渲染
lazyLoadImageRender(element: (HTMLElement | Document) = document) 對啟用懶加載的圖片進行渲染
setCodeTheme(codeTheme: string, cdn = options.cdn) 設置代碼主題,codeTheme 參見 options.preview.hljs.style
setContentTheme(contentTheme: string, path: string) 設置內容主題,contentTheme 參見 options.preview.theme.list

? 開發文檔

原理相關

  • 關于所見即所得 Markdown 編輯器的討論
  • Vditor 實現 Markdown 所見即所得
  • Lute 一款對中文語境優化的 Markdown 引擎,支持 Go 和 JavaScript

環境

  1. 安裝 node LTS 版本
  2. 下載最新代碼并解壓
  3. 根目錄運行 npm install
  4. npm run start 啟動本地服務器,打開 http://localhost:9000
  5. 修改代碼
  6. npm run build 打包代碼到 dist 目錄

CDN 切換

由于使用了按需加載的機制,默認 CDN 為 https://cdn.jsdelivr.net/npm/vditor@版本號

如果代碼有修改或需要使用自建 CDN 的話,可按以下步驟進行操作:

  • 初始化時,需對 optionsIPreviewOptions 中的 cdnemojiPath, themes 進行配置
  • highlightRender , mathRender , abcRender , chartRender , mermaidRenderflowchartRendermindmapRendergraphvizRendersetCodeThemesetContentTheme 方法中需添加 cdn 參數
  • 將 build 成功的 dist 目錄或 jsDelivr 中的 dist 目錄拷貝至正確的位置

升級

版本升級時請仔細閱讀 CHANGELOG 中的升級部分

Ⓜ️ Markdown 使用指南

  • 基礎語法
  • 擴展語法
  • 速查手冊

?️ 社區

  • 官網
  • 討論區
  • 報告問題

? 授權

Vditor 使用 MIT 開源協議。

? 鳴謝

  • Lute:? 一款結構化的 Markdown 引擎,支持 Go 和 JavaScript
  • highlight.js:JavaScript syntax highlighter
  • mermaid:Generation of diagram and flowchart from text in a similar manner as Markdown
  • incubator-echarts:A powerful, interactive charting and visualization library for browser
  • abcjs:JavaScript library for rendering standard music notation in a browser

?️ 歷史

我們在開發 Sym 的初期是直接使用 WYSIWYG 富文本編輯器的。那時候基于 HTML 的編輯器非常流行,項目中引用起來也很方便,也符合用戶當時的使用習慣。

后來,Markdown 的崛起逐步改變了大家的排版方式。再加上我們其他幾個項目都是面向程式員用戶的,所以遷移到 md 上也是大勢所趨。我們選擇了 CodeMirror,這是一款優秀的編輯器,它對開發者提供了豐富的編程接口,對各種瀏覽器的兼容性也比較好。

再后來,隨著我們項目業務需求方面的沉淀,使用 CodeMirror 有時候會感到比較“笨重”。比如要實現 @自動完成用戶名列表、插入 Emoji、上傳文件等就需要比較深入的二次開發,而這些業務需求恰恰是很多項目場景共有且必備的。

終于,我們決定開始在 Sym 中自己實現編輯器。隨著幾個版本的迭代,Sym 的編輯器也日趨成熟。在我們運營的社區YouMeLive上陸續有人問我們是否能將編輯器單獨抽離出來提供給大家使用。與此同時,我們的前端主程 V 同學對于維護分散在各個項目中的編輯器也感到有點力不從心,外加對 TypeScript 的好感,所以就決定使用 ts 來實現一個全新的瀏覽器端 md 編輯器。

于是,Vditor 就這樣誕生了。

53 条回复 A文章作者 M管理員
  1. 終于等到你 ?

  2. 本來早就想抽出來的,要不在 B3log 開源的幾個項目中維護很頭痛。以后只需要維護一個,然后升級以下就好了。

  3. 晚點也在我的項目上試試,現在的 Markdown 編輯器不是功能不全就是 bug 多或者不維護

  4. 謝謝支持

  5. 哈哈,Vditor 很棒!

  6. 在焦點處插入內容應該是 insertValue 吧

    • 初始化對象,可參考 static.js

    此鏈接 404

  7. 文字錯誤:接觸編輯器禁用,「接觸」->「解除」

  8. 前端是這樣傳送的

        const formData = new FormData();
        for (let i = 0, iMax = uploadFileList.length; i < iMax; i++) {
            formData.append("file[]", uploadFileList[i]);
        }
         xhr.send(formData);