• 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;
    
    }

     赞赏支持

  • 相关阅读:
    js 数组,字符串,json互相转换
    数据库相关概念
    信号量,Event, 定时器
    解决Navicat远程连接mysql很慢的方法
    Ubuntu安装mycli,让mysql命令行可以自动提示
    Requests模块调用接口
    selenium chrome浏览器对应chrome版本
    selenium 元素定位+显示等待 方法封装
    smtplib 发送文本文件和附件文件 的类方法封装
    python 数据库的方法封装
  • 原文地址:https://www.cnblogs.com/resolvent/p/7138139.html
Copyright © 2020-2023  润新知