quill parchment
栏目: JavaScript · 发布时间: 5年前
内容简介:Parchment是Quill的文档模型。是一个和DOM树对应的平行树结构,给内容编辑器Quill提供有用的功能。一个Parchment 树是由Blots组构成。Blot是一个DOM节点的对应物。Blots可以提供结构,格式化,或内容。Attributor可以提供轻量级的格式化信息。Parchment tree是DOM tree的对应,二者关系紧密。
概念介绍
Parchment是Quill的文档模型。是一个和DOM树对应的平行树结构,给内容编辑器Quill提供有用的功能。
一个Parchment 树是由Blots组构成。Blot是一个DOM节点的对应物。Blots可以提供结构,格式化,或内容。Attributor可以提供轻量级的格式化信息。
Parchment tree是DOM tree的对应,二者关系紧密。
官方示例
LinkBlot
import Parchment from 'parchment'; class LinkBlot extends Parchment.Inline { static create(url) { let node = super.create(); node.setAttribute('href', url); node.setAttribute('target', '_blank'); node.setAttribute('title', node.textContent); return node; } static formats(domNode) { return domNode.getAttribute('href') || true; } format(name, value) { if (name === 'link' && value) { this.domNode.setAttribute('href', value); } else { super.format(name, value); } } formats() { let formats = super.formats(); formats['link'] = LinkBlot.formats(this.domNode); return formats; } } LinkBlot.blotName = 'link'; LinkBlot.tagName = 'A'; Parchment.register(LinkBlot);
常见问题
富文本编辑器为什么需要自己的一套文档模型?
为什么必要?
为了提供一致的编辑体验,你需要一致的数据和可预测的行为。但是DOM在这两方面都不完美。所以现代的编辑器通过管理自己的文档模型来表示内容。
它的价值?
提供一致的数据和可预测的行为
如何构造出一套文档模型?如何与DOM建立关系?
需要定义出一套基础抽象节点类型, 一套基础的Attributor
ParentBlot, ContainerBlot, LeafBlot, EmbedBlot, ScrollBlot, BlockBlot, InlineBlot, TextBlot Attributor ClassAttributor StyleAttributor
然后会依赖于这些基础节点类型,来构造出一些实际节点类型。Quill中定义了一些实际节点
BlockBlot => Block EmbedBlot => BlockEmbed EmbedBlot => Break ContainerBlot => Container EmbedBlot => Cursor EmbedBlot => Embed InlineBlot => Inline ScrollBlot => Scroll TextBlot => Text
在新建Blot时会新建DOM节点,此时会将其挂到Blot的domNode属性上。
源码分析
基础设计
目录结构
- src - attributor - attributor.ts - class.ts - store.ts - style.ts - blot - abstract - blot.ts - container.ts - format.ts - leaf.ts - shadow.ts - block.ts - embed.ts - inline.ts - scroll.ts - text.ts - collection - linked-list.ts - linked.node.ts - parchment.ts - registry.ts
类图完整版
类图简易版
在parchment.ts中对外导出的有四类东西。
-
节点Blot
- ParentBlot 【父级节点】能对子节点进行增,删,改,移动,查
- ContainerBlot 【容器节点】
- LeafBlot 【叶节点】
- EmbedBlot 嵌入式节点 【可格式化的叶节点】
- ScrollBlot root【文档的根节点,不可格式化】
- BlockBlot 块级 【可格式化的父级节点】
- InlineBlot 内联 【可格式化的父级节点】
- TextBlot 文本【叶节点】
-
属性Attributor
- Attributor 【一种代表格式的方法】
- ClassAttributor 【使用classname模式来代表格式】
- StyleAttributor 【使用内联样式来代表格式】
- AttributorStore 【节点的attributes管理器】在BlockBlot InlineBlot中使用到了
-
注册中心
- Registry 【static blots = new WeakMap<Node, Blot>, attributes,classes,tags,types 】
-
类型常量Scope
- Scope
从一个例子看源码流程
let Inline = Quill.import('blots/inline'); class BoldBlot extends Inline { } BoldBlot.blotName = 'bold'; BoldBlot.tagName = 'strong'; class ItalicBlot extends Inline { } ItalicBlot.blotName = 'italic'; ItalicBlot.tagName = 'em'; Quill.register(BoldBlot); Quill.register(ItalicBlot); let quill = new Quill('#editor-container'); $('#bold-button').click(function() { quill.format('bold', true); }); $('#italic-button').click(function() { quill.format('italic', true); });
- 依赖于Quill提供的Inline类,构造了BoldBlot, ItalicBlot类,并注册到Quill, 会注册出formats/blod, formats/italic(是在Parchment导出的Registry中注册)
- 传入dom id, 构造出一个Quill实例quill。 这里会初始化大量属性,和它内部的模块,注册一些事件,传入id的dom会插入Quill自己的dom, 并绑定上了一些事件。
- 给指定id的dom绑定click事件,click触发时执行quill的格式化方法(里面会做一些判断,看是否有selection, 进行对应的格式化)。
quill.format分两种情况
A. 选中部分内容后,执行格式化。代码流程:
this.editor.formatText -> [this.scroll.formatAt, this.update(delta)] -> scrollBlot.formatAt -> parent.formatAt -> inline.formatAt -> inline.format(DOM修改)
quill.format('bold', true)
本质上会找到BoldBlot,然后执行它的format方法(格式化选中部分),同步更新delta, 真实的修改DOM,给selection添加strong标签。
delta同步和DOM同步是彼此独立的,delta同步相对简单一些(但会做一些组合优化)
const delta = new Delta().retain(index).retain(length, clone(formats)); return this.update(delta);`
B. 未选中内容,执行格式化。
未选中内容是对光标进行格式化。 this.selection.format -> this.cursor.format
。即会对光标后新写的内容对应格式化。
另一个例子
class DividerBlot extends BlockEmbed { } DividerBlot.blotName = 'divider'; DividerBlot.tagName = 'hr'; $('#divider-button').click(function() { let range = quill.getSelection(true); quill.insertText(range.index, '\n', Quill.sources.USER); quill.insertEmbed(range.index + 1, 'divider', true, Quill.sources.USER); quill.setSelection(range.index + 2, Quill.sources.SILENT); });
insertEmbed基本流程: quill.insertEmbed -> this.editor.insertEmbed -> [this.scroll.insertAt, this.update(delta)] -> 创建DOM,插到指定位置
同样的,创建DOM,更新delta都会做的。
参考资料
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
智能优化算法及其应用
王凌 / 清华大学出版社 / 2001-10 / 22.00元
智能优化算法及其应用,ISBN:9787302044994,作者:王凌著一起来看看 《智能优化算法及其应用》 这本书的介绍吧!