富文本编辑器
为什么需要富文本编辑器?它的需求源于内容创作的复杂性和多样性 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、结构化的富文本上传到后台中可以根据自定义属性进行处理
