Skip to content

富文本编辑器

为什么需要富文本编辑器?它的需求源于内容创作的复杂性和多样性 textarea标签无法实现:

  • 格式:加粗、颜色
  • 多媒体嵌入
  • 复杂排版
  • 结构化内容

quill

核心架构

基于 Delta 数据格式(增量)

json
{
  ops: [
    { insert: "Hello " },
    { insert: "World", attributes: { bold: true } },
    { insert: "\n" }
  ]
}
  • 内容完全由 Delta 描述
  • 每次操作都生成 Delta
  • 历史记录是一系列 Delta

设计思路:简单直接

设计目标:提供稳定的 Delta 操作模型

  • 核心:操作 → Delta → 渲染
  • 优点:一致性高,易于理解
  • 缺点:灵活性有限

tiptap

核心架构

基于 ProseMirror 的文档模型(树形结构)

json
{
  type: "doc",
  content: [
    {
      type: "paragraph",
      content: [
        { type: "text", text: "Hello " },
        {
          type: "text",
          text: "World",
          marks: [{ type: "bold" }]
        }
      ]
    }
  ]
}
  • 文档是严格的树形结构
  • 有 Schema 验证
  • 支持复杂嵌套结构

设计思路:灵活强大

设计目标:构建结构化文档编辑器

  • 核心:Schema → 文档树 → 视图
  • 优点:高度灵活,支持复杂需求
  • 缺点:学习曲线陡峭

选择建议

选择 Quill 当:

  • 需要简单的富文本编辑
  • 对性能要求高但结构不复杂
  • 团队前端经验有限

选择 TipTap 当:

  • 需要严格的文档结构
  • 构建复杂的编辑器
  • 需要高度自定义
  • 需要良好的TypeScript支持

现代趋势:

  • 新项目更倾向于 TipTap(生态更活跃)
  • Quill 在维护模式下,但依然稳定

两者都是优秀的选择,关键是匹配项目需求。对于大多数现代应用,特别是需要复杂功能或协作的,TipTap 通常是更好的长期选择。

基于quill editor的行格式化编辑器

在小说、影视、文章的剧本当中,有时候需要按照特定的文本格式进行自定义样式转换,如:当此行内容的前三个字符为“标题:”时,此行样式为加粗、20字号大小

当选择quill editor来实现时,具体步骤如下:

1、新增自定义属性

js
import Quill from 'quill'
const Parchment = Quill.import('parchment')
export const elementTagAttribute = new Parchment.Attributor.Attribute('elementTag', 'element-tag', {
  scope: Parchment.Scope.INLINE
})

2、判断指定内容是否符合此格式、符合则进行格式化处理

js
// 场次(场景、剧情)标题
const SCENE_TITLE_REGEX = /^\s*(?:场景[::]([^\n\r]+)|[[【]场景[::]([^\n\r]+)[\]】]$)/
const checker = (quill, blot, text = '') => {
  return (
    SCENE_TITLE_REGEX.test(text)
  )
    ? text
    : ''
}
const lint = (quill, index, text = '') => {
  const match = text.match(SCENE_TITLE_REGEX)
  const title = match[1] || match[2] || ''
  const formattedText = `【场景:${title.trim()}】`

  replaceText(quill, index, text.length, formattedText)

  return formattedText
}
export function execFormat (quill, blot, index, text, cb) {
  const txt = checker(quill, blot, text)

  if (txt) {

    formatTxt = txt

    if (lint) formatTxt = lint(quill, index, formatTxt)

    return formatTxt
  }

  return txt
}

3、满足此格式则对此行增加自定义属性:

js
export const elementTagName = elementTagAttribute.keyName
// 格式化选择内容
quill.format(elementTagName, 'custom-title', Quill.sources.SILENT)
// 格式化此行内容
quill.formatLine(index, 1, elementTagName, 'custom-title', Quill.sources.SILENT)

4、为此自定义属性内容设置对应样式:

css
[element-tag="custom-title"] {
  font-weight: bold;
  font-size:20px;
}

5、结构化的富文本上传到后台中可以根据自定义属性进行处理