quill
API驱动设计,自定义内容和格式化,跨平台,易用. html
CKEditor
功能强,配置灵活,ui漂亮,兼容性差vue
TinyMCE
文档好,功能强,bug少,无外部依赖。react
UEditor
功能齐全,可是不维护了,依赖jquery,自定义起来较复杂。jquery
常见功能git
- quill.js - core.js - blots/ - block.js - break.js - container.js - cursor.js - embed.js - inline.js - scroll.js - text.js - core/ - editor.js - emitter.js - instance.js - logger.js - module.js - quill.js - selection.js - theme.js - formats/ - align.js - background.js - blockquote.js - bold.js - code.js - color.js - direction.js - font.js - formula.js - header.js - image.js - indent.js - italic.js - link.js - list.js - script.js - size.js - strike.js - table.js - underline.js - video.js - modules/ - clipboard.js 剪切板(复制粘贴) - history.js 撤销重作 - keyboard.js 功能快捷键,可自定义 - syntax.js 代码块语法高亮,依赖highlight.js - table.js 表格 - toolbar.js 工具栏(选项可配置,工具栏html可自定义,自定义选项handlers) - uploader.js - themes/ - base.js - bubble.js - snow.js - ui/ - color-picker.js - icon.picker.js - icons.js - picker.js - tooltip.js
比较重要的是 quill.js, core.js, core/editor.js, core/quill.js, formats/, blots/
这些目录和文件。github
Quill中的blots【block, break, container, cursor, embed, inline, scroll, text】
和formats中的【blockquote, bold, code, formula, header, image, italic, link, list, script, strike, table, underline, video】
主要利用parchment对外提供的基础Blot来做为可供继承的Blot父类api
formats中的【align, background, color, direction, font, indent, size】
使用 parchment对外提供的【Attributor, ClassAttributor, StyleAttributor】
来控制样式数组
parchment提供的Registry是用来进行blot和format的注册。微信
delta既是表达文档,又表达文档修改。数据结构
delta做为一种描述内容修改的数据结构,承担用户操做和DOM修改之间语言的做用
delta又做为编辑器当前内容的 一种表达方式(数据源)
简易流程:dom mutations -> delta
ScrollBlot是最顶层的ContainerBlot, 即root Blot, 包裹全部blots, 而且管理编辑器中的内容变化。
ScrollBlot会建立一个 MutationObserver
, 用来监控DOM更新。DOM更新时会调用ScrollBlot的update方法。在Quill的scroll blot中重写了update方法,其中对外抛出SCROLL_UPDATE事件和mutations参数
。
if (mutations.length > 0) { this.emitter.emit(Emitter.events.SCROLL_UPDATE, source, mutations); }
而后editor会监听SCROLL_UPDATE事件
,而后触发editor的update方法,传入mutations参数,而后在editor的update方法中,会依据mutations构建出对应的delta数组
,与已有的delta合并,使当前delta保持最新。
// core/quill.js // 监听dom修改后触发的SCROLL_UPDATE事件 this.emitter.on(Emitter.events.SCROLL_UPDATE, (source, mutations) => { const oldRange = this.selection.lastRange; const [newRange] = this.selection.getRange(); const selectionInfo = oldRange && newRange ? { oldRange, newRange } : undefined; modify.call( this, // 依据mutations来同步更新editor对应的delta () => this.editor.update(null, mutations, selectionInfo), source, ); }); // core/editor.js // 更新this.delta为最新 update(change, mutations = [], selectionInfo = undefined) { //...some code return change; }
简易流程:delta -> blots -> dom
例如这个API; setContents(delta: Delta, source: String = 'api'): Delta
setContents传入delta后,会遍历delta数组, 生成相应的Blot, Attributor, 而后生成DOM结构
,而后进行format
简易源码流程:
quill.setContents -> this.editor.applyDelta -> this.scroll.formatAt
vue-quill-practice
中的src/components/RichTextEditor/index.vue
提供一些示例, 可是由于是从业务代码中拿出来的,缺乏不少依赖的东西,没法运行。仅供参考,提供思路。
文档:官方文档,github, 中文文档(有人翻译了,可是翻译的很差,直接看官方的吧)
插件:https://github.com/quilljs/aw...
结合vue:vue-quill-editor
结合react: react-quill