quill深刻淺出

背景分析/技術選型

quill
API驅動設計,自定義內容和格式化,跨平臺,易用. html

CKEditor
功能強,配置靈活,ui漂亮,兼容性差vue

TinyMCE
文檔好,功能強,bug少,無外部依賴。react

UEditor
功能齊全,可是不維護了,依賴jquery,自定義起來較複雜。jquery

功能分析

常見功能git

  1. 基本文本編輯功能(加粗,加斜,字體大小,顏色等等)
  2. 文本從word複製粘貼過來後保持格式
  3. 撤銷重作
  4. 擴展能力(自定義toolbar,插件(內容的擴展性))
  5. 高級功能(公式,表格等等)

結構分析

目錄結構

- quill.js
- core.js
- blots/
    - block.js
    - break.js
    - container.js
    - cursor.js
    - embed.js
    - inline.js
    - scroll.js
    - text.js
- core/
    - editor.js
    - emitter.js
    - instance.js
    - logger.js
    - module.js
    - quill.js
    - selection.js
    - theme.js
- formats/
    - align.js
    - background.js
    - blockquote.js
    - bold.js
    - code.js
    - color.js
    - direction.js
    - font.js
    - formula.js
    - header.js
    - image.js
    - indent.js
    - italic.js
    - link.js
    - list.js
    - script.js
    - size.js
    - strike.js
    - table.js
    - underline.js
    - video.js
- modules/
    - clipboard.js 剪切板(複製粘貼)
    - history.js 撤銷重作
    - keyboard.js 功能快捷鍵,可自定義
    - syntax.js 代碼塊語法高亮,依賴highlight.js
    - table.js 表格
    - toolbar.js 工具欄(選項可配置,工具欄html可自定義,自定義選項handlers)
    - uploader.js
- themes/
    - base.js
    - bubble.js
    - snow.js
- ui/
    - color-picker.js
    - icon.picker.js
    - icons.js
    - picker.js
    - tooltip.js

比較重要的是 quill.js, core.js, core/editor.js, core/quill.js, formats/, blots/這些目錄和文件。github

Quill與parchment的關係

Quill中的blots【block, break, container, cursor, embed, inline, scroll, text】和formats中的【blockquote, bold, code, formula, header, image, italic, link, list, script, strike, table, underline, video】主要利用parchment對外提供的基礎Blot來做爲可供繼承的Blot父類api

formats中的【align, background, color, direction, font, indent, size】使用 parchment對外提供的【Attributor, ClassAttributor, StyleAttributor】 來控制樣式數組

parchment提供的Registry是用來進行blot和format的註冊。微信

Quill與Delta的關係

delta既是表達文檔,又表達文檔修改。數據結構

delta做爲一種描述內容修改的數據結構,承擔用戶操做和DOM修改之間語言的做用

delta又做爲編輯器當前內容的 一種表達方式(數據源)

難點

dom修改後,如何同步到delta?

簡易流程:dom mutations -> delta

ScrollBlot是最頂層的ContainerBlot, 即root Blot, 包裹全部blots, 而且管理編輯器中的內容變化。
ScrollBlot會建立一個 MutationObserver, 用來監控DOM更新。DOM更新時會調用ScrollBlot的update方法。在Quill的scroll blot中重寫了update方法,其中對外拋出SCROLL_UPDATE事件和mutations參數

if (mutations.length > 0) {
  this.emitter.emit(Emitter.events.SCROLL_UPDATE, source, mutations);
}

而後editor會監聽SCROLL_UPDATE事件,而後觸發editor的update方法,傳入mutations參數,而後在editor的update方法中,會依據mutations構建出對應的delta數組,與已有的delta合併,使當前delta保持最新。

// core/quill.js
// 監聽dom修改後觸發的SCROLL_UPDATE事件
this.emitter.on(Emitter.events.SCROLL_UPDATE, (source, mutations) => {
  const oldRange = this.selection.lastRange;
  const [newRange] = this.selection.getRange();
  const selectionInfo =
    oldRange && newRange ? { oldRange, newRange } : undefined;
  modify.call(
    this,
    // 依據mutations來同步更新editor對應的delta
    () => this.editor.update(null, mutations, selectionInfo),
    source,
  );
});

// core/editor.js
// 更新this.delta爲最新
update(change, mutations = [], selectionInfo = undefined) {
    //...some code
    
    return change;
}

delta修改後,如何同步到dom?

簡易流程:delta -> blots -> dom

例如這個API; setContents(delta: Delta, source: String = 'api'): Delta

setContents傳入delta後,會遍歷delta數組, 生成相應的Blot, Attributor, 而後生成DOM結構,而後進行format

簡易源碼流程:

quill.setContents -> this.editor.applyDelta -> this.scroll.formatAt

業務實踐

vue-quill-practice
中的src/components/RichTextEditor/index.vue提供一些示例, 可是由於是從業務代碼中拿出來的,缺乏不少依賴的東西,沒法運行。僅供參考,提供思路。

主要功能

  • magicUrl (url文本被自動轉爲url連接,可點擊跳轉)
  • imageDrop (圖片拖放,複製粘貼上傳)
  • imageResize (圖片縮放,水平位置調整)
  • mention (@人員)
  • 預覽模式點擊圖片自動彈層放大顯示(依賴v-viewer)
  • 自定義link按鈕行爲,點擊彈窗填寫連接名稱和url, 肯定後插入編輯器
  • 自定義image按鈕行爲,點擊選擇圖片並上傳
  • 自定義Quote Blot(引用塊, 相似企業微信的引用塊)

生態

文檔:官方文檔,github, 中文文檔(有人翻譯了,可是翻譯的很差,直接看官方的吧)
插件:https://github.com/quilljs/aw...
結合vue:vue-quill-editor
結合react: react-quill

參考資料

深刻理解quilljs
github quill

相關文章
相關標籤/搜索