DevUI 是一款面向企業中後臺產品的開源前端解決方案,它倡導沉浸
、靈活
、至簡
的設計價值觀,提倡設計者爲真實的需求服務,爲多數人的設計,拒絕譁衆取寵、取悅眼球的設計。若是你正在開發 ToB
的工具類產品
,DevUI 將是一個很不錯的選擇!css
富文本編輯器大概是最複雜、使用場景卻極廣的組件了。前端
能夠說富文本編輯器讓Web數據錄入充滿了無限的想象空間,若是隻有文本框、下拉框這些純文本的數據錄入組件,那麼Web的數據錄入能力將極大地受限。咱們將沒法在網頁上插入圖片、視頻這些富文本內容,更沒法插入自定義的內容。node
富文本編輯器讓Web內容編輯變得更輕鬆、更高效,咱們幾乎能夠在富文本編輯器中插入任何你想插入的內容,圖片、視頻、超連接、公式、代碼塊,都不在話下,甚至還能夠插入表格、PPT、思惟導圖,甚至3D模型這種超複雜的自定義內容。git
富文本編輯器的場景在Web上也是隨處可見,寫文章、寫評論、意見反饋、錄需求單,都須要使用到富文本。npm
本文結合DevUI團隊在富文本組件中的實踐,從使用場景、技術選型,再到對Quill的擴展,以及Quill的基本原理,跟你們分享Quill富文本編輯器的那些事兒。segmentfault
本文主要由如下部分組成:數組
如下內容來自Kagol
在華爲 HWEB 大前端技術分享會
上的演講。框架
咱們的需求:編輯器
UEditor
Draft.js
和Slate
CKEditor
Trix
,弱支持表格的Etherpad
和Prosemirror
,以及表格功能收費的TinyMCE
Quill
和wangEditor
兩款編輯器可選,wangEditor
的擴展性和生態不如Quill
,因此最終選擇Quill
做爲富文本組件的基座Document:https://quilljs.com/svg
介紹Quill的API:
介紹如何擴展Quill:
npm i quill
@import 'quill/dist/quill.snow.css';
import Quill from 'quill';
new Quill('#editor', { theme: 'snow' });
效果圖:
好比我想在編輯器裏插入標籤
好比我想在編輯器裏插入附件
好比我想在編輯器中插入表情
相似語雀的評論:https://www.yuque.com/yuque/blog/sguhed
好比我想插入B站這種個性化的分割線
好比我想插入知乎這樣的超連接卡片
咱們從如何插入表情入手,一塊兒看看怎麼在Quill中插入自定義的內容。
要在Quill中插入表情,只須要如下四步:
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網站複製
效果以下:
工具欄上已經多了一個表情的按鈕,而且可以響應鼠標點擊事件,下一步就是要
編寫插入表情的具體邏輯,這涉及到Quill的自定義內容相關的知識。
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;
有了EmojiBlot,要將其插入Quill編輯器中,還須要將這個ES6類註冊到Quill中。
import EmojiBlot from './formats/emoji'; Quill.register('formats/emoji', EmojiBlot);
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', }); },
源碼連接:https://gitee.com/kagol/quill-demo
也歡迎關注咱們DevUI組件庫的官網,瞭解更多有趣又實用的開源組件!
DevUI官網:https://devui.design
最後講一講Quill的基本原理。
經過Delta數據模型來描述富文本內容及其變化
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’)
渲染富文本內容的基本原理:
遍歷Delta數組,將其中描述的內容一個一個應用(插入/格式化/刪除)到編輯器中。
詳情可參考DevUI專欄文章:
擴展Quill的方式:
詳情可參考DevUI專欄文章:
THANK YOU!