Quill富文本編輯器的實踐 - DevUI

DevUI 是一款面向企業中後臺產品的開源前端解決方案,它倡導沉浸靈活至簡的設計價值觀,提倡設計者爲真實的需求服務,爲多數人的設計,拒絕譁衆取寵、取悅眼球的設計。若是你正在開發 ToB工具類產品,DevUI 將是一個很不錯的選擇!css

Kagol.png

引言

富文本編輯器大概是最複雜、使用場景卻極廣的組件了。前端

能夠說富文本編輯器讓Web數據錄入充滿了無限的想象空間,若是隻有文本框、下拉框這些純文本的數據錄入組件,那麼Web的數據錄入能力將極大地受限。咱們將沒法在網頁上插入圖片、視頻這些富文本內容,更沒法插入自定義的內容。node

富文本編輯器讓Web內容編輯變得更輕鬆、更高效,咱們幾乎能夠在富文本編輯器中插入任何你想插入的內容,圖片、視頻、超連接、公式、代碼塊,都不在話下,甚至還能夠插入表格、PPT、思惟導圖,甚至3D模型這種超複雜的自定義內容。git

富文本編輯器的場景在Web上也是隨處可見,寫文章、寫評論、意見反饋、錄需求單,都須要使用到富文本。npm

本文結合DevUI團隊在富文本組件中的實踐,從使用場景、技術選型,再到對Quill的擴展,以及Quill的基本原理,跟你們分享Quill富文本編輯器的那些事兒。segmentfault

本文主要由如下部分組成:數組

  1. 富文本編輯器的使用場景
  2. 技術選型
  3. 咱們爲何選擇Quill
  4. 如何擴展Quill
  5. Quill基本原理

如下內容來自Kagol華爲 HWEB 大前端技術分享會上的演講。框架

富文本編輯器的使用場景

  • 博客文章
  • Wiki詞條
  • 工做項描述
  • 測試用例步驟
  • 反饋意見
  • 評論

1.png

2.png

3.png

技術選型

咱們的需求:編輯器

  • 開源協議友好
  • Angular框架或框架無關
  • 靈活可擴展
  • 支持插入/編輯表格和圖片
  • 插件豐富,生態好

4.png

5.png

選型分析

  • 首先排除官方不維護的UEditor
  • 而後排除React框架專屬的Draft.jsSlate
  • 接着排除開源協議不友好的CKEditor
  • 因爲咱們的業務場景豐富,須要富文本插入/編輯表格的功能,因此還須要排除不支持表格的Trix,弱支持表格的EtherpadProsemirror,以及表格功能收費的TinyMCE
  • 最後只剩下QuillwangEditor兩款編輯器可選,wangEditor的擴展性和生態不如Quill,因此最終選擇Quill做爲富文本組件的基座

爲何選擇Quill?

  • BSD協議,商業友好
  • 文檔詳細,上手快
  • API驅動,擴展性好
  • 插件豐富,生態好

文檔詳細

Document:https://quilljs.com/svg

介紹Quill的API:

1622088667748.png

介紹如何擴展Quill:

7.png

上手快

  • 安裝Quill:npm i quill
  • 引入樣式:@import 'quill/dist/quill.snow.css';
  • 引入Quill:import Quill from 'quill';
  • 初始化Quill:new Quill('#editor', { theme: 'snow' });

效果圖:

8.png

API驅動,擴展性好

9.png

10.png

插件豐富,生態好

11.png

擴展Quill

插入標籤

好比我想在編輯器裏插入標籤

12.png

上傳附件

好比我想在編輯器裏插入附件

13.png

插入表情

好比我想在編輯器中插入表情

相似語雀的評論:https://www.yuque.com/yuque/blog/sguhed

14.png

個性分割線

好比我想插入B站這種個性化的分割線

15.png

超連接卡片

好比我想插入知乎這樣的超連接卡片

16.png

如何插入表情?

咱們從如何插入表情入手,一塊兒看看怎麼在Quill中插入自定義的內容。

要在Quill中插入表情,只須要如下四步:

  • 第一步:自定義工具欄按鈕
  • 第二步:自定義Blot內容EmojiBlot
  • 第三步:在Quill註冊EmojiBlot
  • 第四步:調用Quill的API插入表情

第一步:自定義工具欄按鈕

const quill = new Quill('#editor', {
  theme: 'snow',
  modules: {
    // 配置工具欄模塊
    toolbar: {
      container: [ …, [ 'emoji' ] ], // 增長一個按鈕
      handlers: {
        // 添加按鈕的處理邏輯
        emoji() {
          console.log('插入表情');
        }
      }
    },
  }
});

給工具欄按鈕增長圖標

// 擴展Quill內置的icons配置
const icons = Quill.import('ui/icons');
icons.emoji = ‘<svg>…</svg>’; // 圖標的svg能夠從iconfont網站複製

效果以下:

17.png

工具欄上已經多了一個表情的按鈕,而且可以響應鼠標點擊事件,下一步就是要
編寫插入表情的具體邏輯,這涉及到Quill的自定義內容相關的知識。

第二步:自定義Blot內容EmojiBlot

Quill中的Blot就是一個普通的ES6 Class,因爲表情和圖片的差異就在於:

Quill內置的圖片格式不支持自定義寬高,而咱們要插入的表情是須要特定的寬高的。

所以咱們能夠基於Quill內置的image格式來擴展。

emoji.ts

import Quill from 'quill';

const ImageBlot = Quill.import('formats/image');

// 擴展Quill內置的image格式
class EmojiBlot extends ImageBlot {
  static blotName = 'emoji'; // 定義自定義Blot的名字(必須全局惟一)
  static tagName = 'img'; // 自定義內容的標籤名

  // 建立自定義內容的DOM節點
  static create(value): any {
    const node = super.create(value);
    node.setAttribute('src', ImageBlot.sanitize(value.url));
    if (value.width !== undefined) {
      node.setAttribute('width', value.width);
    }
    if (value.height !== undefined) {
      node.setAttribute('height', value.height);
    }
    return node;
  }
  
  // 返回options數據
  static value(node): any {
    return {
      url: node.getAttribute('src'),
      width: node.getAttribute('width'),
      height: node.getAttribute('height')
    };
  }
}

export default EmojiBlot;

第三步:在Quill註冊EmojiBlot

有了EmojiBlot,要將其插入Quill編輯器中,還須要將這個ES6類註冊到Quill中。

import EmojiBlot from './formats/emoji';
Quill.register('formats/emoji', EmojiBlot);

第四步:調用Quill的API插入表情

EmojiBlot註冊到Quill中以後,Quill就能認識它了,也就能夠調用Quill的API將其插入到編輯器中。

emoji(): void {
  console.log(‘插入表情');
  // 獲取當前光標位置
  const index = this.quill.getSelection().index;
  // 在當前光標處插入emoji(blotName)
  this.quill.insertEmbed(index, 'emoji', {
    url: 'assets/emoji/good.png',
    width: '64px',
  });
},

效果圖

圖片.png

Demo源碼

源碼連接:https://gitee.com/kagol/quill-demo

也歡迎關注咱們DevUI組件庫的官網,瞭解更多有趣又實用的開源組件!

DevUI官網:https://devui.design

Quill基本原理

最後講一講Quill的基本原理。

基本原理

  • 使用Delta數據模型描述富文本內容及其變化,以保證行爲的可預測
  • 經過Parchment對DOM進行抽象,以保證平臺一致性
  • 經過Mutation Observe監聽DOM節點的變化,將DOM的更改同步到Delta數據模型中

18.png

Quill如何表達編輯器內容?

Delta數據模型

經過Delta數據模型來描述富文本內容及其變化

19.png

Delta 是JSON的一個子集,只包含一個 ops 屬性,它的值是一個對象數組,每一個數組項表明對編輯器的一個操做(以編輯器初始狀態爲空爲基準)。

{
  "ops": [
    { "insert": "Hello " },
    { "insert": "World", "attributes": { "bold": true } },
    { "insert": "\n" }
  ]
}

修改編輯器內容

好比咱們把加粗的"World"改爲紅色的文字"World",這個動做用 Delta 描述以下:

{
  "ops": [
    { "retain": 6 },
    { "retain": 5, "attributes": { "color": "#ff0000" } }
  ]
}

意思是:保留編輯器最前面的6個字符,即保留"Hello "不動,保留以後的5個字符"World",並將這些字符設置爲字體顏色爲"#ff0000"。

刪除編輯器內容

若是要刪除"World"呢?

{
  "ops": [
    { "retain": 6 },
    { "delete": 5 }
  ]
}

即:保留前面6個字符(’Hello ’),刪除以後的5個字符(’World’)

Quill如何渲染內容?

渲染富文本內容的基本原理:
遍歷Delta數組,將其中描述的內容一個一個應用(插入/格式化/刪除)到編輯器中。

詳情可參考DevUI專欄文章:

《Quill的內容渲染機制》

Quill如何擴展編輯器的能力?

擴展Quill的方式:

  • 經過自定義Blot格式來擴展編輯器的內容
  • 經過自定義模塊來擴展編輯器的功能

詳情可參考DevUI專欄文章:

《現代富文本編輯器Quill的模塊化機制》

THANK YOU!

相關文章
相關標籤/搜索