zoukankan      html  css  js  c++  java
  • 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;
    
    }

     赞赏支持

  • 相关阅读:
    句法分析树标注集
    LaTeX入门教程(二)
    LaTeX入门教程(一)
    汉语词性对照表[北大标准/中科院标准]
    Python版C语言词法分析器
    QT5.4 计算器程序 打包&发布,解决dll的最新解决方案
    解决Android SDK Manager更新(一个更新Host的程序的原理实现和源码)
    增加个人博客地址,欢迎访问
    Matlab R2012b启动出现License Manager Error -15
    C++中二维数组的动态创建与处理
  • 原文地址:https://www.cnblogs.com/resolvent/p/7138139.html
Copyright © 2011-2022 走看看