沐鳴代理:_Quill 實踐指南
quill 定製富文本編輯器
很多時候 <textarea> 並不能滿足我們對文本輸入的需求,當我們需要為輸入的文本添加格式時,我們需要使用像 quill 這樣的富文本編輯器來完成富文本的輸入。
本文將會詳細的講解如何使用 quill 定製一個自己的富文本編輯器。
這裏面定製了兩個特殊的功能(添加卡片、添加圖片牆),感興趣的同學可以先看一下實現后的效果
線上效果
github 倉庫
接下來將會講解如何在 quill 的基礎上實現定製化的富文本編輯器。
quill 簡介
一個好的富文本編輯器的標誌就是它能夠支持多少種格式,而 quill 支持無限種類的格式。你可以在 quill 上定製任意種類的文本。並且,如果你不想自定義個任何功能,那麼 quill 也是極易上手的,如下的一段代碼就可以創建一個簡單的富文本編輯器了。
var quill = new Quill('#editor', {
modules: { toolbar: true },
theme: 'snow'
})
quill 自帶了一套數據系統方便我們自由的擴展想要的功能,Parchment 和 Delta
Parchment
Parchment 是抽象的文檔模型,是一種與 Dom 樹很類似的結構,Parchment 用於存儲我們的文檔結構,另外 Parchment 由 Blot 組成,關於 Blot 可以理解為 Parchment 的 Node 節點,Blot 中可以包含結構、內容、樣式等。
Delta
Delta 是一個 json 結構的數據,用來記錄編輯器產生的變化。Delta 中的每一項數據代表了一次操作。
同時我們也可以通過 Delta 操作編輯器中的內容。
new Delta().retain(2).delete(4)
retain(2) 表示跳過編輯器中前 2 個 Blot
delete(4) 表示刪除編輯器中的接下來的 4 個 Blot
Blot
Blot 是 Parchment 的組成部分,是一種類似於 Dom Node 的結構,Blot 有其自己的接口規範
在 Parchment 中主要有3種 Blot
Block Blot
塊級元素的基本實現(可以在其內部插入其他的 Blot)
Inline Blot
內聯元素的基本實現(可以在其內部插入其他 內聯 的 Blot)
Embed Blot
非文本恭弘=叶 恭弘子節點的基本實現(這種 Blot 內部不允許再插入其他的 Blot,通常用來實現 Dom 中 <img> <video> 這類標籤對應的 Dom 結構)
Blot 一般通過調用 Parchment.create() 創建,我們可以覆蓋 create 方法,並在覆蓋的方法中通過 super 調用被我覆蓋的方法,來保留 Blot 的默認行為。
一般情況下我們還需要實現 value() 方法,value() 方法返回 create() 方法中的參數值
class MyBlot extends Parchment.Block {
static create(value){
const node = super.create();
// 接下來自定義其他功能
node.setAttribute('attribute',value)
}
value(node){
return node.getAttribute('attribute')
}
}
在我們自定義了一個 Blot 后,這時我們還不能在 quill 中使用它,還需要進行註冊。
MyBlot.blotName = 'MyBlot'
MyBlot.tagName= 'div'
MyBlot.className= "my-blot"
Quill.register(MyBlot)
關於 Quill 的前置知識介紹這麼多,下面會通過一個 Demo 來加深理解.
如何在 Quill 上定製功能
quill 提供了非常細粒度、定義良好的 API,我們可以在此基礎之上定製化開發自己的富文本編輯器。(環境為 vue + iview ,使用 iview 進行輔助樣式開發)
首先我們從最簡單的 demo 入手
<template>
<div id="editor" class="editor"></div>
</template>
<script>
import Quill from "quill";
export default {
mounted() {
const quill = new Quill("#editor", {
theme: "snow",
placeholder: "請在此開始編輯..."
});
}
};
</script>
這是一個默認參數條件下的一個富文本編輯器,我們首先對 Toolbar 進行替換,Toolbar 是 modules 的一部分。
我們需要在新建 quill 實例的時候覆蓋原來的 toolbar,並使用的自己的 toolbar 元素。
<template>
<div class="container">
<div id="toolbar">
<Tooltip content="加粗" placement="bottom">
<button class="ql-bold"></button>
</Tooltip>
<Tooltip content="傾斜" placement="bottom">
<button class="ql-italic"></button>
</Tooltip>
<Tooltip content="下劃線" placement="bottom">
<button class="ql-underline"></button>
</Tooltip>
<Tooltip content="刪除線" placement="bottom">
<button class="ql-strike"></button>
</Tooltip>
</div>
<div id="editor" class="editor"></div>
</div>
</template>
<script>
import Quill from "quill";
export default {
mounted() {
const quill = new Quill("#editor", {
theme: "snow",
modules: {
toolbar: "#toolbar"
},
placeholder: "請在此開始編輯..."
});
}
};
</script>
<style lang="less" scoped></style>
會將我們的 toolbar 的樣式變成如下的樣子。
quill 在初始化時會讀取 #toolbar 元素,並獲取其子節點的 classNames,對於 ql-bold ,quill 會截取 ql-之後的部分,並且和已經註冊的 handlers 做匹配,上面的 bold italic underline strike 存在註冊好的 handler。當我們點擊 toolbar 中的元素時便會調用 handler 對富文本內容進行格式化。
當我們需要添加一個本不存在的格式化效果時我們還需要在 modules 中補充它的 handler,下面添加一個可以添加卡片的按鈕,並添加其對應的 handler。
<template>
<div class="”container“">
<div id="toolbar">
<Tooltip content="添加卡片" placement="bottom">
<button class="ql-card">
<Icon type="md-card" />
</button>
</Tooltip>
</div>
<div id="editor" class="editor"></div>
</div>
</template>
<script>
import Quill from "quill";
export default {
mounted() {
const quill = new Quill("#editor", {
theme: "snow",
modules: {
toolbar: {
container: "#toolbar",
handlers: {
card: () => { // 屬性名稱要與 ql-xxx 對應
console.log(`點擊了 card`);
}
}
}
},
placeholder: "請在此開始編輯..."
});
}
};
</script>
<style lang="less" scoped></style>
接下來我們為這個按鈕添加實際的效果。
在 Quill 中,使用 Blots 表示節點,我們可以認為 Blots 對應 Dom 中的 Node。當我們需要在 quill 中添加一自定義的 Blots 節點時,我們需要讓其繼承自 Blots 節點。
const BlockEmbed = Quill.import('blots/block/embed')
function customCard(node) {
// 在一個節點中插入自定義的 dom
const leftDiv = document.createElement('div')
leftDiv.className = 'media-container'
const mediaDiv = document.createElement('div')
mediaDiv.style['background-image'] = `url(${value.image})`
mediaDiv.className = 'media'
leftDiv.appendChild(mediaDiv)
const rightDiv = document.createElement('div')
rightDiv.className = 'content-container'
const titleP = document.createElement('p')
titleP.className = 'title'
titleP.innerText = value.title
const authorP = document.createElement('p')
authorP.className = 'author'
authorP.innerText = value.author
const contentP = document.createElement('p')
contentP.className = 'content'
contentP.innerText = value.content
rightDiv.appendChild(titleP)
rightDiv.appendChild(authorP)
rightDiv.appendChild(contentP)
node.appendChild(leftDiv)
node.appendChild(rightDiv)
}
// 自定義卡片節點
class CardBlot extends BlockEmbed {
static create(value) {
const node = super.create()
// 新建節點時傳入的數據
node.dataset.title = value.title
node.dataset.image = value.image
node.dataset.content = value.content
node.dataset.author = value.author
customizeCard(node)
node.setAttribute('contenteditable', false) // 設置該節點不可編輯
return node
}
static value(node) {
// 這裏需要返回 create 函數中傳入的數據
return node.dataset
}
}
CardBlot.blotName = 'card' // quill 中的標記名稱
CardBlot.tagName = 'div' // dom 節點名稱
CardBlot.className = 'card' // dom 中真實的 class 名稱
Quill.register(CardBlot)
同時我們還需要添加對應的 handler
const CARD_INFO = {
title: 'Quill 編輯器',
author: 'jhchen',
content:
'Quill是一種現代的富文本編輯器,旨在實現兼容性和可擴展性。它由Jason Chen和Byron Milligan創建,並由Slab积極維護。 ',
image:
'http://neau-lib-static.test.upcdn.net/quill/resource/1576812308405-0.0544z7sqq9au-quill.png'
}
new Quill('#editor', {
theme: 'snow',
modules: {
toolbar: {
container: '#toolbar',
handlers: {
card: () => {
const addRange = this.quill.getSelection() || 0 // 獲取當前光標選中的位置
this.quill.insertEmbed(
addRange,
'card',
CARD_INFO,
Quill.sources.USER
) // 插入 card blots
this.$nextTick(() => {
this.quill.setSelection(addRange + 1, Quill.sources.SILENT)
}) // 插入完成后將光標向後移動一位
}
}
}
},
placeholder: '請在此開始編輯...'
})
至此我們就可以通過點擊 card 圖標來添加一個 card 了,但是這個 card 還沒有添加樣式,我們手動在显示 card 頁面上添加樣式就大功告成了。
通過這種方式,我們可以便可以在 quill 添加任意類型的內容。
最後
文章中的代碼片段有時候看起來並不清晰,如果感興趣,可以去看一看這個小 demo: 線上效果,github 倉庫。
對 quill 的使用有個整體印象,甚至可以方便的 copy 代碼,在 demo 中實現了一個 圖片牆 的功能,幫助大家開闊思路。
原文:https://segmentfault.com/a/1190000021549175
站長推薦
1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲
2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入
鏈接: http://www.fly63.com/article/detial/7228