美文网首页
右击选中标红,反选和取消

右击选中标红,反选和取消

作者: lantern王 | 来源:发表于2019-05-05 13:59 被阅读0次

    前提:公司需要开发一个给内部使用的文本标记工具,主要是给标记同事选取关键字并入库。主要使用到了window的selection。记录下我的第一个前端需求。

    <script>
    //ready入口
    (document).ready(function () {("#sign").click(function () {
    if (signed) {
    cancelSign(true);
    }else{
    sign();
    }
    });
    ("#cancelRecent").click(function () { cancelRecentSign(); });("#cancelAll").click(function () {
    cancelAll();
    });
    $("#sign").css("cursor", "default");
    });

            //订阅对象
            // signStartIndex:标记文本起始下标
            //signEndIndex:标记文本结束下标
            //signText:标记文本
            //signContent:标记文本前后文
            // content:全文本信息
            //element:当前元素标签,订阅后及为父容器标签
            function SignBean(signStartIndex,signEndIndex,signText,signContent,content) {
                this.signStartIndex = signStartIndex;
                this.signEndIndex = signEndIndex;
                this.signText = signText;
                this.signContent = signContent;
                this.content = content;
            }
    
            //根元素
            var rootElement = document.getElementById("rootDivId");
            //订阅数组 用于存储订阅标记
            var signedArray = new Array();
            //点击订阅
            function sign() {
                element.innerHTML = innerHTML;
                mSignBean.content = rootElement.innerHTML;
                signedArray.push(mSignBean);
                console.log("signedArray length:" + signedArray.length);
            }
            //判断是否已订阅,已订阅返回true ,未订阅返回false
            function isSigned(signBean) {
                if (signedArray.length == 0) {
                    return false;
                } 
                for (let index = 0; index < signedArray.length; index++) {
                    signBean == signedArray[index];
                    return true;
                }
                return false;
            }
    
            function indexOf(signBean) {
                for (let index = 0; index < signedArray.length; index++) {
                    signBean == signedArray[index];
                    return index;
                }
              }
            //取消订阅
            function cancelSign(bool) {
                // console.log("parentNede innerhtml:" + parentNode.innerHTML);
                var rootNodeInnerHTML = rootElement.innerHTML;
                var signSearchText = '<span data-yifangbao="nlp" style="color:red">' + signText + "</span>";
                signStartIndex = rootNodeInnerHTML.indexOf(signSearchText);
                signEndIndex = signStartIndex + signSearchText.length;
                contentStart = signStartIndex > 10 ? signStartIndex - 10:0;
                contentEnd =  rootNodeInnerHTML.length - signEndIndex > 10 ? signEndIndex + 10: rootNodeInnerHTML.length;
                signContent =  rootNodeInnerHTML.substring(contentStart,contentEnd);
                mSignBean = new SignBean(signStartIndex,signEndIndex,signText,signContent,rootElement.innerHTML);
                console.log("取消标记:" + "; start:" + mSignBean.signStartIndex + "; end:" + mSignBean.signEndIndex + "; signtext:" +mSignBean.signText + "; signContent:" + mSignBean.signContent);
                if (!bool || isSigned(mSignBean)) {
                    console.log("sisigned:" + true);
                    //取消标记
                    signed = true;
                    var cancelBeforeText =  rootNodeInnerHTML.substring(0,mSignBean.signStartIndex);
                    var cancelAfterText =  rootNodeInnerHTML.substring(mSignBean.signEndIndex, rootNodeInnerHTML.length);
                     rootNodeInnerHTML = cancelBeforeText + mSignBean.signText + cancelAfterText;
                    rootElement.innerHTML =  rootNodeInnerHTML;
                    if (bool) {
                        console.log("signedarray length:" + signedArray.length);
                        var index = indexOf(mSignBean);
                        signedArray.splice(index,1);
                        console.log("signedarray length:" + signedArray.length);
                    }
                } 
            }
    
            //取消全部订阅
            function cancelAll() {
                while (signedArray.length > 0) {
                    var signbean = signedArray.pop();
                    signText = signbean.signText;
                    cancelSign(signbean.element,false);
                }
              }
    
            //取消最近一个订阅  
            function cancelRecentSign() {
                if (signedArray.length > 0) {
                    var signbean = signedArray.pop();
                    signText = signbean.signText;
                    cancelSign(signbean.element,false);
                }  
                
            }  
    
            //提取到函数外面作为全局变量
            var rm = document.getElementById("rightMenu");
            // 鼠标右键点击展示自定义选项
            document.documentElement.oncontextmenu=function (e) {
                //获取选中selection对象
                selection = selectText();
                console.log(selection);
                
    
                //获取当前结点文本节点
                var currentNodeText = selection.baseNode.data;
                console.log("currentNodeText:" + currentNodeText);
                //获取焦点元素 innerhtml 内容
                console.log("e.target:" + e.target);
                var  currentElementHTML = e.target.innerHTML;
                console.log("currentElementHTML:" + currentElementHTML);
                //获取当前结点文本在焦点元素 内容的位置下标
                var currentNodeIndex =  currentElementHTML.indexOf(currentNodeText);
                //获取选中文本在当前结点文本的起始下标
                var anchorOffset = selection.anchorOffset;
                //获取选中文本在当前结点文本的结束下标
                var focusOffset = selection.focusOffset;
    
                //判断选取文本正序或倒序选取,并重置起始和结束下标
                if (focusOffset < anchorOffset) {
                    var tem = anchorOffset;
                    anchorOffset = focusOffset;
                    focusOffset = tem;
                }
                console.log("anchoroffset:" + anchorOffset + "; focusoffset:" + focusOffset);
                //获取选中文本
                signText = currentNodeText.substring(anchorOffset,focusOffset);
                console.log("signText:" + signText);
    
                //判断当前标记行为是否合法 如果非法返回不做处理
                if (isIllegal()) {
                    alert("非法操作,不可以跨标签或覆盖标记!");
                    return false;
                }
    
                //如果选中文本为空则不做处理
                if (isNull(signText)) {
                    return true;
                }
    
                //判断是否重复标记
                if (isRepeat()) {
                    alert("非法操作,不可以重复标记!");
                    return false;
                } 
    
                if (signText == currentNodeText && currentNodeText == e.target.innerText && e.target instanceof HTMLSpanElement) {
                    //格式上符合已标记特性
                    
                    parentNode = e.target.parentNode; 
                    var  rootNodeInnerHTML = rootElement.innerHTML;
                    var signSearchText = '<span data-yifangbao="nlp" style="color:red">' + signText + "</span>";
                    signStartIndex =  rootNodeInnerHTML.indexOf(signSearchText);
                    signEndIndex = signStartIndex + signSearchText.length;
                    contentStart = signStartIndex > 10 ? signStartIndex - 10:0;
                    contentEnd =  rootNodeInnerHTML.length - signEndIndex > 10 ? signEndIndex + 10: rootNodeInnerHTML.length;
                    signContent =  rootNodeInnerHTML.substring(contentStart,contentEnd);
                    mSignBean = new SignBean(signStartIndex,signEndIndex,signText,signContent,rootElement.innerHTML);
                    console.log("取消标记:" + "; start:" + mSignBean.signStartIndex + "; end:" + mSignBean.signEndIndex + "; signtext:" +mSignBean.signText + "; signContent:" + mSignBean.signContent);
                    if (isSigned(mSignBean)) {
                        //取消标记
                        signed = true;
                    } 
                }else{
                    signed = false;
                    //格式上不符合已标记特性
                    //获取选中文本在焦点元素 innerhtml 内容中的起始下标
                    signStartIndex = currentNodeIndex + anchorOffset;
                    //获取选中文本在焦点元素 innerhtml 内容中的结束下标
                    signEndIndex = currentNodeIndex + focusOffset;
                    //获取焦点元素 选中内容前的 innerhtml 内容
                    var beforeText =  currentElementHTML.substring(0,signStartIndex);
                    //获取焦点元素 选中内容后的 innerhtml 内容
                    var afterText =  currentElementHTML.substring(signEndIndex, currentElementHTML.length);
                    //标记
                    console.log("标记");
                    //标记选中内容
                    signedText = '<span data-yifangbao="nlp" style="color:red">' + signText + "</span>";
                    //获取signbean的content字段
                    contentStart = signStartIndex > 10 ? signStartIndex - 10:0;
                    contentEnd = currentElementHTML.length - signEndIndex > 10 ? signEndIndex + 10:currentElementHTML.length; 
    
                    signContent = currentElementHTML.substring(contentStart,signStartIndex) + signedText + currentElementHTML.substring(signEndIndex,contentEnd);
                    mSignBean = new SignBean(signStartIndex + 45,signEndIndex + 45,signText,signContent,rootElement.innerHTML,e.target);
                    // e.target.innerHTML = currentElementHTML;
                    //重新拼接innerhtml内容并展示
                    currentElementHTML = beforeText + signedText + afterText;
                    console.log("标记:" + "; start:" + mSignBean.signStartIndex + "; end:" + mSignBean.signEndIndex + "; signtext:" +mSignBean.signText + "; signContent:" + mSignBean.content + "; element:" + mSignBean.element);
                    element = e.target;
                    innerHTML = currentElementHTML;
                }
    
                //兼容Event对象
                e = e || window.event;
                //鼠标坐标
                var mx = e.pageX;
                var my = e.pageY;
                //菜单宽度
                var rmWidth = parseInt(rm.style.width);
                var rmHeight = parseInt(rm.style.height);
                //网页的宽度(高度用同样的方法解决)
                var pageWidth = document.documentElement.clientWidth;
                var pageHeight = document.documentElement.clientHeight;
                // 定位menu显示位置
                if ((mx + rmWidth)< pageWidth) {
                    rm.style.left = mx + "px";
                }else{
                    rm.style.left = (mx-rmWidth) + "px";
                }
                if ((my + rmHeight < pageHeight)) {
                    rm.style.top = my + "px";
                }else{
                    rm.style.top = (my-rmHeight) + "px";
                }
                $("#sign").text(signed ? "取消标记": "标记");
                //3.显示右键菜单
                rm.style.display = "block";
                return false;
            }
            // 单击鼠标 选项消失
            document.documentElement.onclick = function () {
                rm.style.display = "none";
                }
    
            //判断是否非法标记    
            function isIllegal() {
                if (selection.anchorNode != selection.focusNode) {
                    return true;
                } 
                if (selection.anchorNode.parentNode.dataset["yifangbao"] == "nlp" && selection.focusNode.parentNode.dataset["yifangbao"] == "nlp") {
                    if (selection.baseNode.data != signText) {
                        return true;
                    }
                    return false;
                }else if(selection.anchorNode.parentNode.dataset["yifangbao"] == "nlp" || selection.focusNode.parentNode.dataset["yifangbao"] == "nlp"){
                    return true;
                }
                return false;
              }   
              //判断是否重复标记
              function isRepeat() {
                if (signedArray.length < 1 ) return false;
                for (let index = 0; index < signedArray.length; index++) {
                    const element = signedArray[index];
                    if (element.signText === signText) {
                        return true;
                    }
                }
                return false;
            }
            //获取标蓝选中的文字和字符下标
            function selectText() {
                if (window.getSelection) {
                    // 标准浏览器
                    const selection = window.getSelection();
                    return selection;
                }
            }
            // 判断字符串是否为空
            function isNull(signText) {
                if (signText == "" || signText == undefined) {
                    return true;
                }
                var regu = "^[ ]+$";
                var re = new RegExp(regu);
                return re.test(signText);
            }
        
            function isIE() {
                if (!!window.ActiveXObject || "ActiveXObject" in window) {
                    console.log("ie");
                    return true;
                }else{
                    console.log("not ie");
                    return false;
                }
            }
        </script>
    

    项目没有做浏览器兼容问题,也存在一点小问题,自用,希望可以帮助到大家,有错误请指正。

    相关文章

      网友评论

          本文标题:右击选中标红,反选和取消

          本文链接:https://www.haomeiwen.com/subject/vzgcoqtx.html