js注释(包含关键字替换)

思路:

首先查找选中文本是当前html第几个字符,然后进行替换样式(isIE为true代表的是ie浏览器)
1、自定义右键事件
2、获取选中的文本及文本为当前html第几个
3、进行替换并取消文本选中

自定义右键事件

document.oncontentmenu = function(e){
    //判断是否有选中的文本
    if(!this.judgeSelectText(this.getSelectedText())){return false};
    this.getSelectedTextAndCurrentNum();
    let target = e.target;
    //判断创建菜单的类型;dom对象id是否包含"spanId_"
    if(
        this.selectText && 
        ((target.id && target.id.indexOf("spanId_")<0) || !target.id)){
        //创建临时右键菜单
        this.createMenu("add",e,target)
    }else if(target.id && target.id.indexOf("spanId_") > -1){
        this.spanId = target.id;
        this.createMenu("other",e,target)
    }
}.bind(this)

//点击注释操作
document.onmousedown = function(e){
    let target = e.target;
    //添加注释
    if(target.id && target.id.indexOf("addAnnotate") >= -1){
        if(this.selectText != ""){
            //1、打开添加注释弹框,2、设置操作为添加
            this.operation = "add";    
        }else if(target.id && target.id.indexOf("updateAnnotate") >= -1){
            //1、打开修改注释弹框,2、设置操作为修改,3、请求获取注释数据值
            this.operation = "update";    
        }else if(target.id && target.id.indexOf("deleteAnnotate") >= -1){
            //1、打开删除注释弹框,2、设置操作为删除
            this.operation = "delete";    
        }else if(target.id && target.id.indexOf("viewAnnotate") >= -1){
            //1、打开查看注释弹框,2、设置操作为查看,3、请求获取注释数据值
            this.operation = "view";    
        }
    }
}.bind(this)

getSelectedText:获取选中的数据

getSelectedText(){
    if(isIE){
        let selectedText = "";
        if(document.selection){
            selectedText = document.selection.createRange().text;
        }else if(document.getSelection){
            selectedText = document.getSelection().toString();
        }else if(window.getSelection){
            selectedText = window.getSelection().toString();
        }
        return selectedText
    }else{
        let selectObject = window.getSelection();
        let selectedText = selectObject.toString();
        return selectedText
    }
}

judgeSelectText:判断当前选中的数据是否符合规范

judgeSelectText(selectText){
    //判断文本是否多段
    if(selectText.indexOf("\r")>=0 || selectText.indexOf("\n")>=0){
        alert("多段文本不支持添加注释")
        return false;        
    }else if(window.getSelection()){
        //判断当前选中数据是否含有注释字段
        let selection = window.getSelection();
        if(selection.anchorNode){
            //anchorNode:返回该选区起点所在的节点
            //focusNode:返回该选区终点所在的节点
            if(selection.anchorNode.data != selection.focusNode.data){
                alert("选中文本包含已注释的文本");
                return false
            }
        }
    }
    return true
}

getSelectedTextAndCurrentNum:获取当前选中的数据及位置放入内存

getSelectedTextAndCurrentNum(){
    if(isIE){
        //当前selection对象
        let selectText = "";
        let selectObject = null;
        if(document.selection){
            //ie10
            selectText = document.selection.createRange().text;
        }else if(document.getSelection){
            //ie11
            selectText = document.getSelection().toString();
        }else if(window.getSelection){
            selectText = window.getSelection().toString();
        }
        selectObject = document.getSelection()
        if(selectText && selectText != ""){
            this.selectText = selectText;
            //获取比较当前位置数据进行比较
            let compareData = this.getNowSelectionCompareData(selectObject);
            //初始化设置当前位置为0,当选中文本为隐藏状态改变后的数据(dispaly:none-->display:block);
            //隐藏的文本计算不正确,hideCurentNum为隐藏文本数量
            let currentNumber = 0;
            this.hideCurentNum = 0;
            //获取当前是第几个元素
            let range = document.body.createRange();
            currentNumber = this.getIECurrentNum(range,compareData,selectText,0);
            this.currentNum = currentNumber
        }else{
            this.selectText = "";
            this.currentNum = 0
        }
    }else{
        let selectObject = window.getSelection();
        let selectText = selectObject.toString();
        if(selectText && selectText != ""){
            this.selectText = selectText;
            //获取比较当前位置数据进行比较
            let compareData = this.getNowSelectionCompareData(selectObject);
            let currentNumber = 0;
            window.getSelection().removeAllRanges();
            currentNumber = this.getNotIECurrentNum(compareData,selectText,0);
            this.currentNum = currentNumber
        }else{
            this.selectText = "";
            this.currentNum = 0
        }
    }
}

getNowSelectionCompareData:获取比较对象

getNowSelectionCompareData(selection){
    let compareData = {};
    if(selection){
        var flg = selection.anchorOffset < selection.focusOffset;
        compareData = {
            leftPoint:flg ? selection.anchorOffset : selection.focusOffset,
            rightPoint:flg ? selection.focusOffset : selection.anchorOffset,
            leftPointNode:flg ? selection.anchorNode : selection.focusNode,
            rightNode:flg ? selection.focusNode : selection.anchorNode,
        }
        return compareData;
    }
    return null;
}

getIECurrentNum:IE浏览器计算当前选中为第几个compareData

getIECurrentNum(text,compareData,str,n){
    if(text.findText(str)){
        try{
            text.select()
        } catch(e) {
            //报错说明含有隐藏文本
            this.hideCurentNum++;
            text.collapse(false);
            return this.getIECurrentNum(text,compareData,str,n)
        }
        n++;
        var tmpSelection = document.getSelection();
        if(
            tmpSelection.focusNode == compareData.rightNode &&
            tmpSelection.anchorNode == compareData.leftNode &&
            tmpSelection.anchorOffset == compareData.leftPoint &&
            tmpSelection.focusOffset == compareData.rightPoint
        ){
            document.body.createTextRange();
            return n;
        }else{
            text.collapse(false);
            return this.getIECurrentNum(text,compareData,str,n)
        }
    }else{
        document.body.createTextRange();
        text.findText(str);
        return 0;
    }
}

getNotIECurrentNum:获取非ie当前页面选中字符的位置

getNotIECurrentNum(compareData,str,n){
    if(window.find(str,false,false)){
        n++;
        var tmpSelection = widow.getSelection();
        if(
            tmpSelection.focusNode == compareData.rightNode &&
            tmpSelection.anchorNode == compareData.leftNode &&
            tmpSelection.anchorOffset == compareData.leftPoint &&
            tmpSelection.focusOffset == compareData.rightPoint
        ){
            return n;
        }else return this.getNotIECurrentNum(compareData,str,n)
    }else return 0
}

createMenu:创建菜单(根据absolute定位)

createMenu(operation,e,parentNode){
    //屏幕宽度
    let iframeWidth = document.documentElement.clientWidth || 
    window.clientWidth || 
    document.body.clientWidth;
    //新增时,元素距离父元素的高度
    let topDistance = this.isIE 
      ? 10 : 
      e.clientY-parentNode.getBoundingClientRect().top;
    //新增时,元素距离父元素左侧距离
    let rightDistance = parentNode.getBoundingClientReact().right - e.offsetX;
    let leftDistance;
    if(
      parentNode.targetName == "TD" ||
      parentNode.parentNode.targetName == "TD" ||
      parentNode.parentNode.parentNode.targetName == "TD"
    ){
        leftDistance = 
          parentNode.getBoundingClientRect().left < 150 
            ? e.offsetX
            : e.offsetX - 150;
    }else{
        leftDistance = 
          e.offsetX < 300
            ? e.offsetX 
            : rightDistance > 150 
            ? e.offsetX
            : e.offsetX - 150
    }
    //编辑删除查看操作左侧距离
    let otherLeftDistance = 
      iframeWidth - parentNode.getBoundingClientRect().right > 150
        ? 10
        : -150;
    this.removeMenu();
    if(!parentNode) return ;
    parentNode.style.position = "relative";
    let tmpDiv = document.createElement("div");
    if(operation == "add"){
        tmpDiv.className = "previewMenuDiv";
        tmpDiv.style.cssText = 
          "position:absolute;"+
          "left:"+leftDistance+"px;"+
          "top:"+topDistance+"px;"+
          "z-index:99;text-indent:0";
        tmpDiv.innerHTML = 
          "
添加注释
" }else{ tmpDiv.className = "previewMenuDiv"; tmpDiv.style.cssText = "position:absolute;"+ "left:"+otherLeftDistance+"px;"+ "z-index:99;text-indent:0"; tmpDiv.innerHTML = "
查看注释
编辑注释
删除注释
"; } if(parentNode){ parentNode.appendChild(tmpDiv) } this.previewMenu = tmpDiv; }

createMenu:移除菜单

createMenu(){
    if(this.previewMenu){
        this.preview.parentNode.removeChild(this.previewMenu);
        this.previewMenu = null
    }
}

保存注释操作
注释id:spanId = "spanId_"+new Date().getTime();
选中文本:this.selectText;
选中数据为当前html第几个:currentNum;
非ie浏览器隐藏元素查找不到,ie浏览器需加上隐藏元素的个数hideCurrentNum

saveAnnotate(){
    if(this.isIE){
        this.replaceIEHtml(
          this.currentNum + this.hideCurrentNum,
          this.selectText,
          this.spanId
        )
    }else{
        this.replaceNotIEHtml(
          this.currentNum,
          this.selectText,
          this.spanId
        )
    }
}

replaceIEHtml:ie浏览器替换选中的元素

replaceIEHtml(currentNum,str,spanId){
    var textRangeArr = [];
    var range = document.body.crateTextRange();
    textRangeArr = this.getFindTextRange(range,str);
    let newTextRangeArr = [];
    if(textRangeArr.length > 0){
        for(let i = 0;i 0 ? currentNum : 1;
        var nowText = newTextRangeArr[currentNum - 1];
        var replaceSelectHtml = 
          ''+
          str+"";
        if(nowText){
            nowText.pasteHTML(replaceSelectHtml)
        }
    }
}

getFindTextRange:获取当前ie符合条件的ranges

getFindTextRange(range,str){
    var ranges = new Array();
    var dup = range.duplicate();
    var flg = true;
    do{
        var d = dup.duplicate();
        if(d.findText(str)){
            ranges.push(d);
            dup.setEndPoint("StartToEnd",d);
            continue;
        }
        break;
    }while(flg);
    return ranges;
}

replaceNotIEHtml:非ie浏览器替换选中的元素

replaceNotIEHtml(currentNum,str,spanId){
    var selectText = null;
    window.getSelection().removeAllRanges();
    selectText = this.getCurrentSession(str,0,currentNum);
    if(selectText){
        var range = selectText.getRangeAt(0);
        var replaceTempSpan = document.createElement("span");
        replaceTempSpan.id = spanId;
        replaceTempSpan.className = "annotateKeyClass";
        replaceTempSpan.style["background"] = "#f28109";
        replaceTempSpan.innerText = str;
        range.surroundContents(replaceTempSpan)
    }
    window.getSelection().removeAllRanges();
}

getCurrentSession:获取当前注释的选中对象

getCurrentSession(str,n,currentNum){
    if(window.find(str,false,false)){
        n++;
        if(n == currentNum){
            return window.getSelection()
        }
        return this.getCurrentSession(str,n,currentNum)
    }else{
        return null;
    }
}

你可能感兴趣的:(vue.js)