前提:公司需要开发一个给内部使用的文本标记工具,主要是给标记同事选取关键字并入库。主要使用到了window的selection。记录下我的第一个前端需求。
<script>
//ready入口
("#sign").click(function () {
if (signed) {
cancelSign(true);
}else{
sign();
}
});
("#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>
项目没有做浏览器兼容问题,也存在一点小问题,自用,希望可以帮助到大家,有错误请指正。
网友评论