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

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

作者: 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