共计 8216 个字符,预计需要花费 21 分钟才能阅读完成。
思路:
首先查找选中文本是以后 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;}
}
正文完