H5编辑器核心算法和思想-遁地龙卷风

代码和特性在chrome49下测试有效。

文本渲染的本质是对文本节点的渲染,通过浏览器内置的对象Range可以获得选择的起始点、与终止点

 

var range = getRangeObject();
var start = range.startOffset,
end = range.endOffset;
var startContainer = range.startContainer;
var endContainer = range.endContainer;

getRangeObjec代码如下

function getRangeObject(){

if(window.getSelection)
{
var selection = window.getSelection();
if(selection.rangeCount > 0)
{
return selection.getRangeAt(0);
}
}
else if(document.selection)
{
return document.selection.createRange(); 
}
return null;
};
View Code

 

  起始点始终在左面,终止点始终在右面,不受选择方向的影响。
  只有当起始点的开头或终止点的末尾是<br/>时,返回的不是文本节点,可以通过start,end确定br元素的位置分别是startContainer.childNodes[start],endContainer.childNodes[end-1]。返回的是文本节点start表示光标相对于起始文本节点所在的起始位置,end表示光标相对于终止文本节点所在的终止位置。

获得下一个文本节点的算法为

function getNextTextNode(startNode,dir = "nextSibling"){
    //记录startNode变化之前的状态,startNode变化后无效时便于状态的回滚
    let unchangeNode = startNode;
    if(startNode.nodeType == 3){
        startNode = startNode[dir];
    }
    while (true){

        if(startNode == undefined){
            if(unchangeNode == undefined){
                //保护机制
                throw new Error("程序会陷入死循环");
                break;
            }
            /*
                startNode所在的父元素所有选中节点遍历完毕,将sartNode指向父元素的兄弟节点
            */
            let parent = unchangeNode.parentElement;
            unchangeNode = parent;
            startNode = parent[dir];
        }
        else if(startNode.nodeType == 3){
            //文本节点则退出循环
            break;
        }
        else if(startNode.tagName == "BR"){
            //处理单标签,避免不必要的迭代
            unchangeNode = startNode;
            startNode = startNode[dir];
        }
        else if(startNode.nodeType == 1){
            /*
                如果是双标签元素则进入
            */
            unchangeNode = startNode;

            if(dir == "previousSibling"){

                startNode = $(startNode).contents().last().get(0);
            }
            else if(dir == "nextSibling"){
                startNode = $(startNode).contents().first().get(0);
            }
            else {
                //便于错误的定位
                throw new Error("错误的遍历方向:"+dir);
            }
        }
        else {
            //便于错误的定位
            throw new Error("不期待的元素类型=》"+startNode);

        }
    }
    
    return startNode;
    
}

  //上述函数用外部变量+while循环的方式取代递归,加入的保护机制减少误用、潜在bug导致极差的体验。
获得起始节点和结束节点之间的所有文本节点

function getTextNodes(startTextNode,endTextNode){
    let textNodeArray = [];
    let node = startTextNode;
    while (true) {
        node = getNextTextNode(node);

        if(node == endTextNode){
            break;
        }
        textNodeArray.push(node);
    }
    
    return textNodeArray;

}

 赞赏支持

posted @ 2017-07-08 21:49  遁地龙卷风  阅读(645)  评论(2编辑  收藏  举报