思路:
首先查找选中文本是当前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;
}
}