/
CATEGORY
React
/
客製化 Quill 編輯器,並搭配 ant design 製作所見即所得編輯器

客製化 Quill 編輯器,並搭配 ant design 製作所見即所得編輯器

MUKI AI Summary

為了整合公司內部系統,決定使用 Quill 編輯器重寫文章管理系統,因為 Markdown 無法直接調整文字顏色,轉而選擇 WYSIWYG 編輯器。Quill React 因功能齊全且客製化選項多,最終被選為編輯器。

Quill React 安裝簡單,透過 npm 指令即可完成,並內建兩種主題:snow 和 bubble。可自訂工具列,並加入自訂按鈕,如 undo、redo。使用 HTML 可完全客製化工具列內容,但需謹慎考慮。完整程式碼可在 GitHub 和 CodeSandbox 上獲取。...

文章更新說明

因為 quill-react 套件已超過 2 年未更新,因此我改用官方的 Quill 套件,並且重新寫了一篇串接 react 的文章,有興趣的朋友請移駕:在 React 使用 Quill 編輯器,並加入上傳圖片至圖床的功能

緣起

因應公司整合內部系統,所以要重寫文章管理系統,原本是想挑選喜歡的 Markdown 編輯器,但考量到原本存在資料庫的就是 HTML 語法,而且 Markdown 本身無法調整文字顏色,一樣要轉成 HTML 再處理,所以最後還是選擇沿用所見即所得編輯器,也就是我們熟知的 WYSIWYG Rich Editor。

而我花了一些時間,翻了各大 React Editor,最後選擇 Quill React

Quill 的 Github Star 很高,而且還有給 React 專用的 Quill React。此外我看了網站文件,功能蠻齊全,客製化的東西也多,版面也蠻好看的,所以就決定是它了 XXD。

安裝與使用 Quill React 編輯器

Quill 有專門給 React 用的編輯器套件,但有特別強調,必須要有 react 以及 react-dom,而且要有類似 style loader 這種可以讀取 CSS 檔案的 loader

▼ 使用 npm 安裝 Quill React

$ npm install react-quill --save

▼ 使用上也非常簡單,載入元件與設定 value 就能用了。Quill 內建兩種 Theme:snow 以及 bubble,載入對應的 css 檔案,並將 theme 設定為 snow / bubble 即可。

import React, { useState } from 'react'
import ReactQuill from 'react-quill'
// import 'react-quill/dist/quill.bubble.css'
import 'react-quill/dist/quill.snow.css'

function MyComponent() {
  const [value, setValue] = useState('')

  // theme="bubble"
  return <ReactQuill theme="snow" value={value} onChange={setValue} />
}

▼ theme snow 示意圖,是一般常見的所見即所得編輯器版面,將工具列固定在上面

▼ theme bubble 示意圖,跟現在新的筆記軟體編輯器類似,反白文字後才會跳出工具列

自訂工具列項目

Quill 的 API 直接提供了自訂工具列的方法,可以任意排列組合,非常方便!

function App() {
  const [value, setValue] = useState('')
  // 宣告 modules 以自訂工具列
  const modules = {
    toolbar: [
      ['bold', 'italic', 'underline', 'strike'], // 粗體, 斜體, 底線, 刪除線
      [{ header: 1 }, { header: 2 }], // 標題
      [{ 'size': ['small', false, 'large', 'huge'] }] // 內文尺寸,false 表示預設值
    ]
  }

  return (
    <div className="w-full">
      <ReactQuill theme="snow" value={value} modules={modules} onChange={setValue} />
    </div>
  )
}

▼ 這是我自訂的工具列

用 HTML 客製化你的工具列

因為 Quill 的方便,讓我異想天開的思考,能不能在工具列上加入我自訂的按鈕或其他設定?

答案是可以的!我們可以改用 HTML 完全修改與調整工具列的內容,只是如果改用 HTML,等於整個要重寫 XXD....,建議大家三思而後行。

我客製化的工具列有:

因為內容不難,這邊就直接上 code,另外我使用的是 ant design 框架,大家可以照自己的框架需求調整 import 內容

▼ 把工具列拉成一個元件,只放工具列的內容

import { useState } from "react"
import { Quill } from "react-quill"
import { Button, Modal } from 'antd'
import { InfoCircleOutlined } from '@ant-design/icons'

const CustomUndo = () => (
  <svg viewBox="0 0 18 18">
    <polygon className="ql-fill ql-stroke" points="6 10 4 12 2 10 6 10" />
    <path
      className="ql-stroke"
      d="M8.09,13.91A4.6,4.6,0,0,0,9,14,5,5,0,1,0,4,9"
    />
  </svg>
)

const CustomRedo = () => (
  <svg viewBox="0 0 18 18">
    <polygon className="ql-fill ql-stroke" points="12 10 14 12 16 10 12 10" />
    <path
      className="ql-stroke"
      d="M9.91,13.91A4.6,4.6,0,0,1,9,14a5,5,0,1,1,5-5"
    />
  </svg>
)

function undoChange() {
  this.quill.history.undo()
}

function redoChange() {
  this.quill.history.undo()
}

// 調整字體尺寸,改用 px 表示
const Size = Quill.import("formats/size")
Size.whitelist = ["15px", "18px", '24px', '32px', '48px']
Quill.register(Size, true)

export const modules = {
  toolbar: {
    container: "#toolbar",
    handlers: {
      undo: undoChange,
      redo: redoChange
    }
  },
  history: {
    delay: 500,
    maxStack: 100,
    userOnly: true
  }
}

// 每新增或移除 Quill Editor 內建的工具,記得要在 formats 做相應的調整
export const formats = [
  "header",
  "size",
  "bold",
  "italic",
  "underline",
  "align",
  "strike",
  "script",
  "blockquote",
  "background",
  "list",
  "bullet",
  "indent",
  "link",
  "image",
  "video",
  "color",
  "code-block"
]

export const QuillToolbar = () => {
  const [isModalOpen, setIsModalOpen] = useState(false)

  return (
    <div id="toolbar">
      <span className="ql-formats">
        <select className="ql-size" defaultValue="medium">
          {/* 對應前面設定的字體尺寸 */}
          <option value="15px">15px</option>
          <option value="18px">18px</option>
          <option value="24px">24px</option>
          <option value="32px">32px</option>
          <option value="48px">48px</option>
        </select>
        <select className="ql-header" defaultValue="">
          <option value="2">大標題</option>
          <option value="3">子標題</option>
          <option value="">內文</option>
        </select>
      </span>
      <span className="ql-formats">
        <button className="ql-bold" />
        <button className="ql-italic" />
        <button className="ql-underline" />
        <button className="ql-blockquote" />
      </span>
      <span className="ql-formats">
        <select className="ql-align" />
        {/* 可以客製化自己喜歡的顏色 */}
        <select className="ql-color">
          <option value="#000000" />
          <option value="#F44336" />
          <option value="#E91E63" />
        </select>
        <select className="ql-background" />
      </span>
      <span className="ql-formats">
        <button className="ql-list" value="ordered" />
        <button className="ql-list" value="bullet" />
        <button className="ql-indent" value="-1" />
        <button className="ql-indent" value="+1" />
      </span>
      <span className="ql-formats">
        <button className="ql-link" />
        <button className="ql-image" />
        <button className="ql-video" />
      </span>
      <span className="ql-formats">
        <button className="ql-clean" />
        <button className="ql-undo">
          <CustomUndo />
        </button>
        <button className="ql-redo">
          <CustomRedo />
        </button>
      </span>
      {/* 我加了一個自訂按鈕 */}
      <span className="ql-formats ql-formats--custom">
        <Button type="primary" onClick={() => { setIsModalOpen(true) }} icon={<InfoCircleOutlined rev={undefined} />}>編輯器使用說明</Button>
      </span>
      <Modal title="編輯器使用說明" width={600} open={isModalOpen} onCancel={() => { setIsModalOpen(false) }} footer={[
        <Button key="submit" type="primary" onClick={() => { setIsModalOpen(false) }}>確認</Button>
      ]}>
        編輯器使用說明 內文
      </Modal>
    </div>
  )
}

export default QuillToolbar

▼ 增加對應的 CSS 樣式

/* =================
@ react-quill
==================== */

.ql-editor h2 {
  font-size: 1.5rem !important;
}

.ql-editor h3 {
  font-size: 1.3rem !important;
}

.ql-size-15px { font-size: 15px; }
.ql-size-18px { font-size: 18px; }
.ql-size-24px { font-size: 24px; }
.ql-size-32px { font-size: 32px; }
.ql-size-48px { font-size: 48px; }

.ql-formats--custom button {
  background: #1677FF !important;
  width: 100% !important;
  height: 32px !important;
  padding: 4px 15px !important;
}

.ql-formats--custom button:hover, .ql-formats--custom button:focus {
  color: #FFF !important;
  background-color: #4096FF !important;
}

▼ 匯入元件

import React, { useState } from 'react'
import ReactQuill from 'react-quill'
import EditorToolbar, { modules, formats } from './components/EditorToolbar'
import 'react-quill/dist/quill.snow.css'

function App() {
  const [value, setValue] = useState('')
  // 記得把剛剛宣告的 modules 註解或是刪除
  // const modules = {
  //   toolbar: [
  //     ['bold', 'italic', 'underline', 'strike'],
  //     [{ header: 1 }, { header: 2 }],
  //     [{ 'size': ['small', false, 'large', 'huge'] }]
  //   ]
  // }

  return (
    <div className="w-full">
      <EditorToolbar />
      <ReactQuill theme="snow" value={value} modules={modules} formats={formats} onChange={setValue} />
    </div>
  )
}

export default App

▼ 最後就可以看到我們客製化的工具列了!

線上範例與下載

我把上面這段程式放在 github 與 codesandbox,有興趣的朋友可以拉下來參考

參考資料

歡迎給我點鼓勵,讓我知道你來過 :)

20
MUKI says:

如果文章有幫助到你,歡迎分享給更多人知道。文章內容皆為 MUKI 本人的原創文章,我會經常更新文章以及修正錯誤內容,因此轉載時建議保留原出處,避免出現版本不一致或已過時的資訊。

本文地址:https://muki.tw/quill-react-ant-design/ 已複製

Subscribe
Notify of
guest

0 則留言
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Copyright © since 2008 MUKI space* / omegaSS theme All Rights Reserved.