思路:
首先查找选中文本是以后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 = "<div id='addAnnotate'>增加正文</div>" }else{ tmpDiv.className = "previewMenuDiv"; tmpDiv.style.cssText = "position:absolute;"+ "left:"+otherLeftDistance+"px;"+ "z-index:99;text-indent:0"; tmpDiv.innerHTML = "<div id='viewAnnotate'>查看正文</div><div id='updateAnnotate'>编辑正文</div><div id='deleteAnnotate'>删除正文</div>"; } 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<textRangeArr.length;i++){ if(textRangeArr[i].offsetLeft != 0 && textRangeArr[i].offsetTop != 0){ newTextRangeArr.push(textRangeArr[i]) } } } if(currentNum <= textRangeArr.length){ currentNum = currentNum > 0 ? currentNum : 1; var nowText = newTextRangeArr[currentNum - 1]; var replaceSelectHtml = '<span id="'+spanId+ '"oncontextmenu="" class="annotateKeyClass" style="background:#f28109">'+ str+"</span>"; 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; }}