内容简介:这篇文章更适合对quill.js已经有一定了解的读者,如果您是正打算调研/学习quill.js,可以通过官方文档或我之前的一篇文章《深入理解quilljs》对为了更清晰的介绍
前言
这篇文章更适合对quill.js已经有一定了解的读者,如果您是正打算调研/学习quill.js,可以通过官方文档或我之前的一篇文章《深入理解quilljs》对 Quill编辑器 有一定了解后,再来阅读这篇文章。
为了更清晰的介绍 Container 的用法,我选择使用个人基于 quill.js 实现的表格模块 quill-better-table 作为示例来讲解,因为quill.js官方内置的模块都相对简单,难以覆盖各个方面。
quill-better-table 项目地址: github.com/soccerloway…
Container类
Parchemnt是quill.js用于描述/管理编辑器内容结构及对应DOM树的底层依赖 , quill.js 中内置的Blot类均继承自 Parchment 的基础类,这些基础内继承自 Parchemnt 的抽象类。关于Container类的继承关系如下:
其中, ShadowBlot 是所有 blot (Inline、Block、Embed、Container等)的父类。实际上,在Quill/blots的源码中, Container类 (quill.js)仅仅是继承了 Parchment 中的Container类,没有任何逻辑代码。故我们真正需要了解的是 Parchment 中的 Container类 。
如何定义嵌套结构及原理
接下来,我们来看看表格模块中 单元格行 (TableCellLine)、 单元格 (tableCell)的定义(为避免代码过多,影响阅读体验,format及表格业务逻辑相关的代码会省略掉,完整代码可到 这里 查看):
// TableCellLine class TableCellLine extends Block { ...... // create/formats/optimize等} TableCellLine.blotName = "table-cell-line" TableCellLine.ClassName = "qlbt-cell-line" TableCellLine.tagName = "DIV" // TableCell class TableCell extends Container { ...... checkMerge() { if (super.checkMerge() && this.next.children.head != null) { const thisHead = this.children.head.formats()["table-cell-line"] const thisTail = this.children.tail.formats()["table-cell-line"] const nextHead = this.next.children.head.formats()["table-cell-line"] const nextTail = this.next.children.tail.formats()["table-cell-line"] return ( thisHead.cell === thisTail.cell && thisHead.cell === nextHead.cell && thisHead.cell === nextTail.cell ) } return false } ...... } TableCell.blotName = "table" TableCell.tagName = "TD" TableCell.allowedChildren = [TableCellLine] TableCellLine.requiredContainer = TableCell复制代码
经过上面的定义,最终生成的HTML结构如下:
<td> <div class="qlbt-cell-line"></div> <div class="qlbt-cell-line"></div> </td>复制代码
实际上,控制嵌套结构关系的重点就是:
checkMerge requiredContainer
Blot.requiredContainer
定义该Blot需要被哪一个容器Blot包裹。当该Blot被创建完成后,会执行到 ShadowBlot类 中的 optimize
方法,其主要逻辑就是:检查该Blot的 requiredContainer
是否被设置,并且该Blot的父Blot不是 requiredContainer
设置的Blot类的实例,调用 wrap
方法(wrap的作用就是创建容器Blot实例,插入的该Blot的父级中,然后将该Blot插入到容器中)。
以最终生成前面的HTML结构为例,经过 wrap 的过程后,HTML结构的变化:
checkMerge
该方法就是用于检查是否需要将 这个容器Blot实例 和 它的下一个兄弟Blot实例合并为同一个容器Blot实例 。返回值为 true
则合并。 checkMerge
在Container类的 optimize
方法中调用,紧接 shadowBlot.optimize
过程。当 checkMerge
返回值为 true
时, 下一个兄弟Blot实例 的 children
会被插入到 这个容器实例 中,得到最终HTML结构。
<td> <div class="qlbt-cell-line"></div> <div class="qlbt-cell-line"></div> </td>复制代码
利用checkMerge阻止并列(兄弟关系)的Blot合并
通过上面的定义,我们已经能够得到 一个 支持多行的表格单元格结构了。但在实际的表格中,同一表格行中有若干个单元格,结构如下:
<tr> <td> <div class="qlbt-cell-line">1</div> </td> <td> <div class="qlbt-cell-line">2</div> </td> <td> <div class="qlbt-cell-line">3</div> </td> </tr>复制代码
如何让checkMerge合适的时候返回false,阻止单元格被合并呢?让我们来看看 quill-better-table 中, TableCell类 的 checkMerge
。
checkMerge() { if (super.checkMerge() && this.next.children.head != null) { const thisHead = this.children.head.formats()["table-cell-line"] const thisTail = this.children.tail.formats()["table-cell-line"] const nextHead = this.next.children.head.formats()["table-cell-line"] const nextTail = this.next.children.tail.formats()["table-cell-line"] return ( thisHead.cell === thisTail.cell && thisHead.cell === nextHead.cell && thisHead.cell === nextTail.cell ) } return false }复制代码
示例代码中, checkMerge
方法主要是通过检查当前 tableCell 实例和下一个 tableCell 实例的 children
的formats中属性cell是否相等,相等则合并两个单元格的内容,否则不合并。
实际上, quill-better-table 在定义 TableCellLine
的时候,为它定义了表示单元格和行的唯一标识符,设置到domNode的属性上了,且通过formats方法能够得到这些信息,TableCellLine的DOM结构为:
<div class="qlbt-cell-line" data-row="row-xaes" data-cell="cell-hsop">复制代码
checkMerge
方法既是通过这个唯一符,也是 data-cell
的值来区别 td
是否需要被合并。依照这样的方式,我们就能够一层一层的把表格结构相关的Blot全部定义出来。最终实现在Quill编辑器中插入表格。
注意:像表格这种多层嵌套的内容结构,需要在最内层把唯一标识符都设计好,quill.js中嵌套结构的基础在最内层,然后一层一层wrap和merge,在wrap的时候把所需要的唯一标识符往外传递和使用。
结语
表格相关Blot的定义,以及表格编辑常用功能的实现涉及到的具体细节太多,在这里不赘述,有兴趣的同学可以到我的 quill-better-table 开源项目的源代码中查看具体实现细节,相信对将要在Quill中使用Container的同学大有帮助。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- React Hook 日常使用,一步步创建一个可排序表格组件
- ElementUI 实现表格可编辑 Editable,增删改查编辑表格Grid
- 开源 UI 库中,唯一同时实现了大表格虚拟化和树表格的 Table 组件 原 荐
- html复杂表格
- PHP基础知识(表格)
- vue导出excel表格
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入理解OpenCV
[巴西]Daniel Lelis Baggio / 刘波 / 机械工业出版社 / 2014-9 / 59
opencv是最常见的计算机视觉库之一,它提供了许多经过优化的复杂算法。本书对已掌握基本opencv技术同时想提高计算机视觉的实践经验的开发者来讲是一本非常好的书。每章都有一个单独的项目,其背景也在这些章节中进行了介绍。因此,读者可以依次学习这些项目,也可以直接跳到感兴趣的项目进行学习。 《深入理解opencv:实用计算机视觉项目解析》详细讲解9个实用的计算机视觉项目,通过本书的学习,读者可......一起来看看 《深入理解OpenCV》 这本书的介绍吧!