前言
最近尝试去写一个富文本编辑器,觉得应该也不难,但没想到还是花了不少时间去写前期的主要逻辑,其间太多的边角逻辑是没有考虑到的。原因是前期走了 很多弯路,单纯的一点一点的去实现功能,有分支功能出现就一点一点的修补,到最后发现代码量很多,逻辑很复杂。最后痛下决心,静下心来分析了一下,思考用 理论逻辑去铺垫根基,才算是构建了一个还算满意的基础逻辑。真心觉得,理论才是一切事情的开始点,缜密的理论逻辑才能建造基乎无bug的代码。
前面的都是些废话,由于该文本编器实现了execCommaond的部分方法,下面的内容相对比较复杂,对实现不感兴趣的可以忽略,如果是妹子可以直接联系笔者交流交流
功能
富文本编辑器实现如下的功能
- 实现fake原生execCommand的能力
- 修改style的能力
其实很多能力,原生的execCommand已经帮我们做好了,但我们的编辑器要有与execCommand相同的能力,以备原生无法实现的时候,我们的编辑器还是可以实现。
API能力
- 标签插入与删除
- style修改
便签的修改能力
比如一段代码
1 |
<div>abcd</div> |
如果abc被选中之后,执行execCommand之后的代码是在abc外包裹一个strong标签
变成
1 |
<div><strong>abc</strong>d</div> |
如果b再次选中执行execCommand(‘bold’)命令后,会变成
1 |
<div><strong>a</strong>b<strong>c</strong></div> |
可以看到原来的strong被分离了,变成单独的两个,还有一些更复杂的情况,如下
1 |
<div><strong>ab<u><strong>cd<u>b<span><strong>pp</strong></span></u><strong></u></strong></div> |
像这个串,如果没有良好的理论基础与抽象建模,靠手动的代码去处理基乎是不可能的。
第一步
串的正则化
如上那个复杂的串,其树结构如下
最上面的是根结点,叶子结点都是文本节点(textNode)
我们可以看到规律
叶子结点向上回溯的过程中,通过的结点会给我们赋予不同的功能,但我们要操作的节点,如果像strong、underline一定程度是与样式有关的,我们把它们称为样式结点
如果我们直接删掉叶子结点最近的祖先中的样式结点,很有可能会影响到其他的叶子结点,这时候我们就要把样式结点的影响最小化,就要先进行正则处理
正则化的过程就是要把样式结点转化到叶子结点的上面,每个样式结点只控制一个我们想要直接操作的叶子结点
如下的转化过程
正则化的过程的同时,我们还要修剪一些无用的结点,比如空的span结点,比如空的textNode,转化完了之后的树,我们处理起来变得很简单
正则化的实现也很简单,从ROOT结点进行中序遍历的算法,即先访问根结点,再从左向右依次访问子结点,然后一直到叶子结点,找出叶子结点的样式结点次续,并删除经过的样式结点,然后把它们插入到每个叶子结点的上面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
var scan = function(node, inhrintStyles){ // 已经是叶子节点了 if(node.nodeType === node.TEXT_NODE){ if(inhrintStyles.length){ leafNodes.push({ inhrintStyles: inhrintStyles.concat([]), node: node }); } // 非叶子节点 }else{ // 如果是style节点 // 标记这是要删除的style节点, if(styleTagNames.indexOf(node.tagName.toLowerCase()) > -1){ // inhrintStyles存在此style 不重复增加 var exists = 0; for(var i = 0; i < inhrintStyles.length; i ++){ if(inhrintStyles[i].tagName === node.tagName){ exists = 1; break; } } if(! exists){ inhrintStyles = inhrintStyles.concat(node); } styleNodes.push(node); } for(var i = 0; i < node.childNodes.length; i ++){ scan(node.childNodes[i], inhrintStyles); } } } } } }发现代码量很多,逻辑很复杂。最后痛下决心,静下心来分析了一下,思考用 理论逻辑去铺垫根基,才算是构建了一个还算满意的基础逻辑。真心觉得,理论才是一切事情的开始点,缜密的理论逻辑才能建造基乎无bug的代码。
前面的都是些废话,由于该文本编器实现了execCommaond的部分方法,下面的内容相对比较复杂,对实现不感兴趣的可以忽略,如果是妹子可以直接联系笔者交流交流 功能富文本编辑器实现如下的功能
其实很多能力,原生的execCommand已经帮我们做好了,但我们的编辑器要有与execCommand相同的能力,以备原生无法实现的时候,我们的编辑器还是可以实现。 API能力
便签的修改能力
如果abc被选中之后,执行execCommand之后的代码是在abc外包裹一个strong标签
如果b再次选中执行execCommand(‘bold’)命令后,会变成
可以看到原来的strong被分离了,变成单独的两个,还有一些更复杂的情况,如下
像这个串,如果没有良好的理论基础与抽象建模,靠手动的代码去处理基乎是不可能的。 第一步串的正则化如上那个复杂的串,其树结构如下 我们可以看到规律叶子结点向上回溯的过程中,通过的结点会给我们赋予不同的功能,但我们要操作的节点,如果像strong、underline一定程度是与样式有关的,我们把它们称为样式结点 正则化的过程就是要把样式结点转化到叶子结点的上面,每个样式结点只控制一个我们想要直接操作的叶子结点 正则化的过程的同时,我们还要修剪一些无用的结点,比如空的span结点,比如空的textNode,转化完了之后的树,我们处理起来变得很简单 正则化的实现也很简单,从ROOT结点进行中序遍历的算法,即先访问根结点,再从左向右依次访问子结点,然后一直到叶子结点,找出叶子结点的样式结点次续,并删除经过的样式结点,然后把它们插入到每个叶子结点的上面
|