亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

富文本編輯器quill.js開發(fā)之自定義格式擴展

 更新時間:2023年08月14日 09:37:11   作者:Grewer  
這篇文章主要為大家介紹了富文本編輯器quill.js開發(fā)之自定義格式擴展,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

鑒于各種繁雜的需求,quill.js 編輯器也面臨著各種挑戰(zhàn),例如我們需要添加“table”布局樣式以適應(yīng)郵件發(fā)送格式,手動擴展表情符號功能等等。本文將對這些可定制化功能進(jìn)行講解和實現(xiàn)。

區(qū)分 format 和 module

首先需要明確的是,我們應(yīng)該清楚自己所需的擴展具體是什么?

比如想要新增一個自定義 emoji, 那么想象一下步驟:

  • 點擊工具欄
  • 彈出彈窗或者對應(yīng)的 popover
  • 在 2 中選中 emoji

這些步驟是一種常見的添加流程。

我們需要明確的是,添加自定義表情符號必然需要一個相應(yīng)的格式。

本文將以 format 為例,對此進(jìn)行詳細(xì)講解。

quill 的格式類型

說起 quill 的格式類型, 他的常用格式可以分成 3 類:

  • Inline

常見的有 BoldColorFont 等等, 不占據(jù)一行的標(biāo)簽, 類似于 html 里 span 的特性, 是一個行內(nèi)樣式, Inline格式之間可以相互影響

  • Block

添加 Block 樣式, 必然會占據(jù)一整行, 并且 Block 樣式之間不能兼容(共存), 常見的有 ListHeaderCode Block 等等

  • Embeds

媒體文件, 常見的有 ImageVideoFormula, 這類格式擴展的比較少, 但是本次要加的 emoji 但是這種格式

自定義樣式

新增 emoji.ts 文件來存儲格式, 關(guān)于他的類型, 我們選擇 Embeds 格式, 使用這種格式有以下原因:

  • 他是一種獨特的類型, 不能和顏色, 字體大小等等用在一起
  • 需要和字體并列, 所以也不能是 Block 類型
import Quill from 'quill';
const Embed = Quill.import('blots/embed');
class EmojiBlot extends Embed {
  static blotName: string;
  static tagName: string;
  static create(value: HTMLImageElement) {
    const node = super.create();
    node.setAttribute('alt', value.alt);
    node.setAttribute('src', value.src);
    node.setAttribute('width', value.width);
    node.setAttribute('height', value.height);
    return node;
  }
  static formats(node: HTMLImageElement) {
    return {
      alt: node.getAttribute('alt'),
      src: node.getAttribute('src'),
      width: node.getAttribute('width'),
      height: node.getAttribute('height'),
    };
  }
  static value(node: HTMLImageElement) {
    // 主要在有初始值時起作用
    return {
      alt: node.getAttribute('alt'),
      src: node.getAttribute('src'),
      width: node.getAttribute('width'),
      height: node.getAttribute('height'),
    };
  }
}
EmojiBlot.blotName = 'emoji';
EmojiBlot.tagName = 'img';
EmojiBlot.className = 'emoji_icon'
export default EmojiBlot;

因為還有正常的圖片類型會使用 img, 這里就需要加上 className, 來消除歧義
一般來說, 新開發(fā)的擴展性類型, 盡量都加上 className

這樣一個 emoji 類型就創(chuàng)建完成了!

最后我們注冊到 Quill 上即可:

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

這里我們在加上自定義的 popover, 用來點擊獲取 emoji:

<Popover content={<div className={'emoji-popover'} onClick={proxyEmojiClick}>
  <img alt={'圖片說明'} width={32} height={32} src="https://grewer.github.io/dataSave/emoji/img.png"/>
  <img alt={'圖片說明'} width={32} height={32} src="https://grewer.github.io/dataSave/emoji/img_1.png"/>
</div>}>
  <button className="ql-emoji">emoji</button>
</Popover>

通過代理的方式, 來獲取 dom 上的具體屬性:

const proxyEmojiClick = ev => {
  const img = ev.target
  if (img?.nodeName === 'IMG') {
    const quill = getEditor();
    const range = quill.getSelection();
    // 這里可以用 img 的屬性, 也可以通過 data-* 來傳遞一些數(shù)據(jù)
    quill.insertEmbed(range.index, 'emoji', {
      alt: img.alt,
      src: img.src,
      width: img.width,
      height: img.height,
    });
    quill.setSelection(range.index + 1);
  }
}

展示下新增 emoji 的效果:

基礎(chǔ)格式說明

我們的自定義格式都是基于 quill 的基礎(chǔ)庫: parchment

這里我們就介紹下他的幾個重要 API:

class Blot {
  // 在手動創(chuàng)建/初始值時, 都會觸發(fā) create 函數(shù)
  static create(value?: any): Node;
  // 從 domNode 上獲取想要的數(shù)據(jù)
  static formats(domNode: Node);
  // static formats 返回的數(shù)據(jù)會被傳遞給 format
  // 此函數(shù)的作用是將數(shù)據(jù)設(shè)置到 domNode
  // 如果 name 是 quill 里的格式走默認(rèn)邏輯是會被正確使用的
  // 如果是特殊的name, 不處理就不會起效
  format(format: name, value: any);
  // 返回一個值, 通常在初始化的時候傳給 static create
  // 通常實現(xiàn)一個自定義格式, value 和 format 使用一個即可達(dá)到目標(biāo)
  value(): any;
}

上述幾個 API 便是創(chuàng)建自定義格式時常用到的

詳情可參考: https://www.npmjs.com/package/parchment#blots

在上文講到了 format 和 value 的作用, 我們也可以對于 EmojiBlot 做出一些改造:

class EmojiBlot extends Embed {
  static blotName: string;
  static tagName: string;
  static create(value: HTMLImageElement) {
    const node = super.create();
    node.setAttribute('alt', value.alt);
    node.setAttribute('src', value.src);
    node.setAttribute('width', value.width);
    node.setAttribute('height', value.height);
    return node;
  }
  static formats(node: HTMLImageElement) {
    return {
      alt: node.getAttribute('alt'),
      src: node.getAttribute('src'),
      width: node.getAttribute('width'),
      height: node.getAttribute('height'),
    };
  }
  format(name, value) {
    if (['alt', 'src', 'width', 'height'].includes(name)) {
      this.domNode.setAttribute(name, value);
    } else {
      super.format(name, value);
    }
  }
}

目前來說, 這兩種方案都能實現(xiàn)我們的 EmojiBlot

當(dāng)然 format 的作用, 并不僅僅在于 新增屬性到 dom 上, 也可以針對某些屬性, 修改、刪除 dom 上的信息

其他格式

上面我們講述了三個常見的格式: Inline 、Embeds 、Block, 其實在 quill 還有一些特殊的 blot:
如: TextBlot 、 ContainerBlot 、 ScrollBlot

其中 ScrollBlot 屬于是所有 blot 的根節(jié)點:

class Scroll extends ScrollBlot {
  // ...
}

Scroll.blotName = 'scroll';
Scroll.className = 'ql-editor';
Scroll.tagName = 'DIV';
Scroll.defaultChild = Block;
Scroll.allowedChildren = [Block, BlockEmbed, Container];

至于 TextBlot, 是在定義一些屬性時常用到的值:

例如源碼中 CodeBlock 的部分:

CodeBlock.allowedChildren = [TextBlot, Break, Cursor];

意味著 CodeBlock 的格式下, 他的子節(jié)點, 只能是文本, 換行, 光標(biāo)
(換行符和光標(biāo)都屬于 EmbedBlot)

這樣就控制住了子節(jié)點的類型, 避免結(jié)構(gòu)錯亂

ContainerBlot

最后要說一下 ContainerBlot, 這是一個在自定義節(jié)點時, 創(chuàng)建 Block 類型時經(jīng)常會用到的值:

在源碼中, 并沒有默認(rèn)的子節(jié)點配置, 所以導(dǎo)致看上去就像這樣, 但其實 container 的自由度是非常強的

這里就給出一個我之前創(chuàng)建的信件格式例子:

在富文本中擴展格式生成能兼容大部分信件的外層格式, 格式要求:

格式占據(jù)一定寬度, 如 500px, 需要讓這部分居中, 格式內(nèi)可以輸入其他的樣式

大家可能覺得簡單, 只需要 div 套上, 再加上一個樣式 width 和 text-align 即可

但是這種方案不太適合郵件的場景, 在桌面和移動端渲染電子郵件大約有上百萬種不同的組合方式。

所以最穩(wěn)定的布局方案只有 table 布局

所以我們開始創(chuàng)建一個 table 布局的外殼:

class WidthFormatTable extends Container {
  static create() {
    const node = super.create();
    node.setAttribute('cellspacing', 0);
    node.setAttribute('align', 'center');
    return node;
  }
}
WidthFormatTable.blotName = 'width-format-table';
WidthFormatTable.className = 'width-format-table';
WidthFormatTable.tagName = 'table';

有了 table 標(biāo)簽, 那么同樣也會需要 tr 和 rd:

也是類似的創(chuàng)建方法:

class WidthFormatTR extends Container {
}
class WidthFormatTD extends Container {
}

最后通過 API 將其關(guān)聯(lián)起來:

WidthFormatTable.allowedChildren = [WidthFormatTR];
WidthFormatTR.allowedChildren = [WidthFormatTD];
WidthFormatTR.requiredContainer = WidthFormatTable;
WidthFormatTD.requiredContainer = WidthFormatTR;
WidthFormatTD.allowedChildren = [WidthFormat];
WidthFormat.requiredContainer = WidthFormatTD;

這一段的含義就是, 保證各個格式的父元素與子元素分別是什么, 不會出現(xiàn)亂套的情況

格式中最后的主體:

class WidthFormat extends Block {
  static register() {
    Quill.register(WidthFormatTable);
    Quill.register(WidthFormatTR);
    Quill.register(WidthFormatTD);
  }
}
WidthFormat.blotName = 'width-format';
WidthFormat.className = 'width-format';
WidthFormat.tagName = 'div';

register 函數(shù)的作用就是在注冊當(dāng)前的 WidthFormat 格式時, 自動注冊其他的依賴格式; 避免人多注冊多次

最后我們新增一個按鈕, 來格式化編輯器內(nèi)容:

const widthFormatHandle = () => {
  const editor = getEditor();
  editor.format('width-format', {})
}

展示下效果:

比較遺憾的是, 同樣作為 Block 格式, 這兩類是不能兼容的, 也就是說在 width-format 格式中, 不能使用 List , Header , Code 這幾項屬性
個人吐槽幾句, 之前嘗試兼容過, 但是在 HTML 和 delta 相互轉(zhuǎn)換時被卡主了, 感覺轉(zhuǎn)換的方式?jīng)]做好

總結(jié)

demo鏈接: 點此查看

本文介紹了 quill.js 在面臨多種需求挑戰(zhàn)時需要添加可定制化功能。quill.js 的常用格式包括 Inline、Block 和 Embeds 三類,而ContainerBlot 則是創(chuàng)建 Block 類型時常用的值,具有極高的自由度。希望本文能夠幫助讀者更好地了解和思考富文本編輯的相關(guān)問題。

以上就是富文本編輯器quill.js開發(fā)之自定義格式擴展的詳細(xì)內(nèi)容,更多關(guān)于富文本編輯器quill.js格式擴展的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論