//表现逻辑层的处理 if (window.location.href.indexOf("backEndAddressServiceWrapper") >= 0) { throw "serviceGrid"; //如果是服务器网页页面, 则不执行工具 } //Vueelement var app; generateToolkit(); //生成Toolkit function generateToolkit() { $(".tooltips").html(`
✍Operation Toolbox (Can drag)

Special click mode

● When your mouse moves to the element, please right-click your mouse button or press F7 on the keyboard to select it.

● You can click the back button to go back to the page

{{initial()}}
● Already selected {{numOfList()}} {{tname()}}, meanwhile we find {{numOfReady()}} element with the same type, you can:
● Already selected the follwoing element, you can:
● Already selected {{numOfList()}} similar elements, and we find other{{numOfReady()}} similar elements, you can:
{{setWidth("350px")}}
{{i["name"]}} Delete
{{valTable[j-1][i-1]}} ×
{{setWidth("290px")}}

{{lastElementXPath()}}

● Please input text:
`); app = new Vue({ el: '#realcontent', data: { option: 0, list: { nl: nodeList, opp: outputParameters }, valTable: [], // 用来存储转换后的para列表 special: false, //是否为特殊selection模式 selectedDescendents: false, // 标记是否选中了子element selectStatus: false, //标记单个element是否点击了采集 page: 0, //默认页面, 1为输入文字页面 text: "", // 记录输入的文字 tNodeName: "", // 记录临时节点列表 nowPath: "", //现在element的xpath }, watch: { nowPath: { //变量发生变化的时候进行一些操作 handler: function(newVal, oldVal) { console.log("xpath:", newVal); } } }, methods: { initial: function() { //每当element是0的时候, 执行值的初始化操作 this.selectedDescendents = false; this.selectStatus = false; this.nowPath = ""; }, confirmCollectSingle: function() { //单element确认采集 collectSingle(); clearEl(); }, confirmCollectMulti: function() { //无规律多element确认采集 collectMultiNoPattern(); clearEl(); }, confirmCollectMultiAndDescendents: function() { //有规律多element确认采集 collectMultiWithPattern(); clearEl(); }, deleteSingleLine: function(event) { //删除单行element let at = new Date().getTime() //流程图送element的时候, 默认的使用不固定循环列表, 但是一旦有删除element的操作发生, 则按照固定element列表采集element index = event.target.getAttribute("index"); let tnode = nodeList.splice(index, 1)[0]; //删掉当前element tnode["node"].style.backgroundColor = tnode["bgColor"]; tnode["node"].style.boxShadow = tnode["boxShadow"]; if (nodeList.length > 1) { // 如果删到没有就没有其他的操作了 handleElement(); if (this.selectedDescendents) { handleDescendents(); //如果之前有Select child elements, 新加入的节点又则这里也需要重新selection子element } } else { this.valTable = []; this.selectStatus = false; clearParameters(); //直接Revoke 重选 } let at2 = parseInt(new Date().getTime()); console.log("delete:", at2, at, at2 - at); }, clickElement: function() { //点击element操作 sendSingleClick(); //先发送数据 nodeList[0]["node"].focus(); //获得element焦点 nodeList[0]["node"].click(); //点击element clearEl(); }, loopClickSingleElement: function() { //循环点击单个element sendLoopClickSingle(this.tname()); //识别下一页,循环点击单个element和点击多个element if (this.tname() != "Elements in next page") { //Elements in next page不进行点击操作 nodeList[0]["node"].focus(); //获得element焦点 nodeList[0]["node"].click(); //点击element } clearEl(); }, loopClickEveryElement: function() { //循环点击每个element sendLoopClickEvery(); //识别下一页,循环点击单个element和点击多个element nodeList[0]["node"].focus(); //获得element焦点 nodeList[0]["node"].click(); //点击element clearEl(); }, setInput: function() { //输入文字 this.page = 1; this.$nextTick(function() { //下一时刻获得焦点 document.getElementById("WTextBox").focus(); }) }, getInput: function() { //得到输入的文字 nodeList[0]["node"].focus(); //获得文字焦点 nodeList[0]["node"].setAttribute("value", this.text); // 设置输入 box内容 input(this.text); // 设置输入 this.text = ""; clearEl(); }, cancelInput: function() { this.page = 0; }, setWidth: function(width) { //根据是否出现表格调整最外 box宽度 $(".tooltips").css("width", width); return ""; }, getText: function() { //采集文字 generateParameters(0, true, false); this.selectStatus = true; clearReady(); }, getLink: function() { //采集linkAddress generateParameters(0, false, true); this.selectStatus = true; clearReady(); }, getOuterHtml: function() { //采集OuterHtml generateParameters(3, true, false); this.selectStatus = true; clearReady(); }, getInnerHtml: function() { //采集InnerHtml generateParameters(2, true, false); this.selectStatus = true; clearReady(); }, tname: function() { let tag = nodeList.length == 0 ? "" : nodeList[0]["node"].tagName; let inputType = nodeList.length == 0 ? "" : nodeList[0]["node"].getAttribute("type"); if (inputType != null) { //如果没有type属性, 则默认为text inputType = inputType.toLowerCase(); } else { inputType = "text"; } if (tag == "") { return "null"; } else if ($(nodeList[0]["node"]).contents().filter(function() { return this.nodeType === 3; }).text().indexOf("Next") >= 0) { this.setWidth("310px"); return "Elements in next page"; } else if (tag == "A") { return "link"; } else if (tag == "IMG") { return "Image"; } else if (tag == "BUTTON" || (tag == "INPUT" && (inputType == "button" || inputType == "submit"))) { return "Button"; } else if (tag == "TEXTAREA" || (tag == "INPUT" && (inputType != "checkbox" || inputType != "ratio"))) { //普通输入 box return "text box"; } else if (tag == "SELECT") { return "selection box"; } else { return "element"; } }, existDescendents: function() { //检测选中的element是否存在子element,Already 经选中了子element也不要再出现了 return nodeList.length > 0 && nodeList[0]["node"].children.length > 0 && !this.selectedDescendents; }, numOfReady: function() { return readyList.length; }, numOfList: function() { return nodeList.length; }, lastElementXPath: function() { //用来显示element的最大最后5个xpath路劲element path = nodeList[nodeList.length - 1]["xpath"]; path = path.split("/"); tp = ""; if (path.length > 5) { //只保留最后五个element path = path.splice(path.length - 5, 5); tp = ".../" } for (i = 0; i < path.length; i++) { path[i] = path[i].split("[")[0]; } path = path.join("/"); path = "Path: " + tp + path; return path; }, cancel: function() { clearEl(); }, specialSelect: function() { //特殊selection模式 if (mousemovebind) { tdiv.style.pointerEvents = "none"; this.special = false; } else { this.special = true; } mousemovebind = !mousemovebind; }, enlarge: function() { // 扩大选区功能, 总是扩大最后一个选中的element的选区 if (nodeList[nodeList.length - 1]["node"].tagName != "BODY") { nodeList[nodeList.length - 1]["node"].style.backgroundColor = nodeList[nodeList.length - 1]["bgColor"]; //之前element恢复原来的背景颜色 nodeList[nodeList.length - 1]["node"].style.boxShadow = nodeList[nodeList.length - 1]["boxShadow"]; //之前element恢复原来的背景颜色 tNode = nodeList[nodeList.length - 1]["node"].parentNode; //向上走一层 if (tNode != NowNode) { //扩大选区之后背景颜色的判断, 当前正好选中的颜色应该是不同的 sty = tNode.style.backgroundColor; } else { sty = style; } nodeList[nodeList.length - 1]["node"] = tNode; nodeList[nodeList.length - 1]["bgColor"] = sty; nodeList[nodeList.length - 1]["xpath"] = readXPath(tNode, 1); //显示 box var pos = tNode.getBoundingClientRect(); div.style.display = "block"; div.style.height = tNode.offsetHeight + "px"; div.style.width = tNode.offsetWidth + "px"; div.style.left = pos.left + "px"; div.style.top = pos.top + "px"; div.style.zIndex = 2147483645; div.style.pointerEvents = "none"; handleElement(); //每次数组element有变动, 都需要重新处理下 oe = tNode; tNode.style.backgroundColor = "rgba(0,191,255,0.5)"; this.selectedDescendents = false; } }, selectAll: function() { //Select Allelement step++; readyToList(step, false); handleElement(); if (this.selectedDescendents) { handleDescendents(); //如果之前有Select child elements, 新加入的节点又则这里也需要重新selection子element } }, revoke: function() { //Revoke selection当前节点 var tstep = step; step--; //步数-1 while (tstep == nodeList[nodeList.length - 1]["step"]) //删掉所有当前步数的element节点 { let node = nodeList.splice(nodeList.length - 1, 1)[0]; //删除数组最后一项 node["node"].style.backgroundColor = node["bgColor"]; //还原原始属性和边 box node["node"].style.boxShadow = node["boxShadow"]; if (NowNode == node["node"]) { style = node["bgColor"]; } //处理Already 经有Select child elements的情况 // if (this.selectedDescendents) { clearParameters(); //直接Revoke 重选 // } } handleElement(); //每次数组element有变动, 都需要重新处理下 }, selectDescendents: function() { //selection所有子element操作 handleDescendents(); } }, }); h = $(".tooldrag").height(); difference = 26 - h; //获得高度值差 if (difference > 0) { $(".tooldrag").css("cssText", "height:" + (26 + difference) + "px!important") } timer = setInterval(function() { //时刻监测相应element是否存在(防止出现如百度一样element消失重写body的情况), 如果不存在, 添加进来 if (document.body != null && document.getElementById("wrapperToolkit") == null) { this.clearInterval(); //先Cancel原来的计时器, 再设置新的计时器 document.body.append(div); //默认如果toolkit不存在则div和tdiv也不存在 document.body.append(tdiv); document.body.append(toolkit); generateToolkit(); // var list = document.getElementsByTagName("a"); // // 对于没有特殊绑定函数的a标签, 使他们在新标签页中打开 // for (var i = 0; i < list.length; i++) { // if (list[i].href.indexOf("javascript") == -1 && list[i].href.indexOf("void") == -1 && list[i].href.indexOf("#") == -1 && list[i].href) { // list[i].setAttribute("target", "_blank"); // } // }; // list = document.getElementsByTagName("form"); // // 对于没有特殊绑定函数的form标签, 使他们在新标签页中打开 // for (var i = 0; i < list.length; i++) { // list[i].setAttribute("target", "_blank"); // }; } }, 3000); } //每次对element进行增删之后需要执行的操作 function handleElement() { clearReady(); //预备element每次处理都先处理掉 if (nodeList.length > 1) { //选中了许多element的情况 app._data.option = relatedTest(); if (app._data.option == 100) { generateMultiParameters(); } else { generateParameters(0); } } else if (nodeList.length == 1) { findRelated(); //寻找和element相关的element } } function clearParameters(deal = true) //清空para列表 { if (deal) //是否Cancel对选中的子element进行处理 { app._data.selectedDescendents = false; } for (o of outputParameterNodes) { o["node"].style.boxShadow = o["boxShadow"]; } outputParameterNodes.splice(0); outputParameters.splice(0); //清空原来的para列表 app._data.valTable = []; //清空展现数组 app._data.selectStatus = false; } //根据nodelist列表内的element生成para列表 //适合:nodelist中的element为同类型element //type:0为全部text 1为节点内直接的文字 2为innerhtml 3为outerhtml //nodetype:0,对应全type0123 //nodetype:1 link, 对应type0123 //nodetype:2 linkAddress 对应type0 //nodetype:3 按钮和输入text box 对应type //nodetype:4 按钮和输入text box 对应type function generateParameters(type, linktext = true, linkhref = true) { clearParameters(false); let n = 1; chrome.storage.local.get({ parameterNum: 1 }, function(items) { let at = parseInt(new Date().getTime()); n = items.parameterNum; for (let num = 0; num < nodeList.length; num++) { let nd = nodeList[num]["node"]; ndPath = nodeList[num]["xpath"]; outputParameterNodes.push({ "node": nd, "boxShadow": nd.style.boxShadow == "" || boxShadowColor ? "none" : nd.style.boxShadow }); nd.style.boxShadow = boxShadowColor; let pname = "text"; let ndText = ""; if (type == 0) { ndText = $(nd).text(); pname = "text"; if (nd.tagName == "IMG") { ndText = nd.getAttribute("src") == null ? "" : $(nd).prop("src"); pname = "Address"; } else if (nd.tagName == "INPUT") { ndText = nd.getAttribute("value") == null ? "" : nd.getAttribute("value"); } } else if (type == 1) { ndText = $(nd).contents().filter(function() { return this.nodeType === 3; }).text().replace(/\s+/g, ''); pname = "text"; if (nd.tagName == "IMG") { ndText = nd.getAttribute("src") == null ? "" : $(nd).prop("src"); pname = "Address"; } else if (nd.tagName == "INPUT") { ndText = nd.getAttribute("value") == null ? "" : nd.getAttribute("value"); } } else if (type == 2) { ndText = $(nd).html(); pname = "Innerhtml"; } else if (type == 3) { ndText = $(nd).prop("outerHTML"); pname = "outerHTML"; } if (num == 0) { //第一个节点新建, 后面的增加即可 if (nd.tagName == "IMG") { //如果element是Image outputParameters.push({ "nodeType": 4, //节点类型 "contentType": type, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径 "name": "para" + (n++) + "_Image" + pname, "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? "" : ndPath, "exampleValues": [{ "num": num, "value": ndText }] }); } else if (nd.tagName == "A") { //如果element是超链接 if (linktext) { outputParameters.push({ "nodeType": 1, "contentType": type, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径 "name": "para" + (n++) + "_link" + pname, "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? "" : ndPath, "exampleValues": [{ "num": num, "value": ndText }] }); } if (linkhref) { outputParameters.push({ "nodeType": 2, "contentType": type, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径 "name": "para" + (n++) + "_linkAddress", "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? "" : ndPath, "exampleValues": [{ "num": num, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") }] }); } } else if (nd.tagName == "INPUT") { //如果element是输入项 outputParameters.push({ "nodeType": 3, "contentType": type, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径 "name": "para" + (n++) + "_" + pname, "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? "" : ndPath, "exampleValues": [{ "num": num, "value": ndText }] }); } else { //其他所有情况 outputParameters.push({ "nodeType": 0, "contentType": type, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径 "name": "para" + (n++) + "_" + pname, "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? "" : ndPath, "exampleValues": [{ "num": num, "value": ndText }] }); } } else { //如果element节点Already 经存在, 则只需要插入值就可以了 if (nd.tagName == "IMG") { //如果element是Image outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText }); } else if (nd.tagName == "A") { //如果element是超链接 outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText }); outputParameters[1]["exampleValues"].push({ "num": num, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") }); } else if (nd.tagName == "INPUT") { //如果element是输入项 outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText }); } else { //其他所有情况 outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText }); } } } let at2 = parseInt(new Date().getTime()); console.log("generateParameters:", at2, at, at2 - at); generateValTable(); console.log(outputParameters); }); } //根据nodelist列表内的element生成para列表 //适合:nodelist中的element为不同类型element function generateMultiParameters() { clearParameters(false); let n = 1; chrome.storage.local.get({ parameterNum: 1 }, function(items) { let at = parseInt(new Date().getTime()); n = items.parameterNum; for (let num = 0; num < nodeList.length; num++) { let nd = nodeList[num]["node"]; ndPath = nodeList[num]["xpath"]; outputParameterNodes.push({ "node": nd, "boxShadow": nd.style.boxShadow == "" || boxShadowColor ? "none" : nd.style.boxShadow }); nd.style.boxShadow = boxShadowColor; ndText = $(nd).text(); if (nd.tagName == "IMG") { //如果element是Image outputParameters.push({ "nodeType": 4, //节点类型 "contentType": 0, // 内容类型 "relative": false, //是否为相对xpath路径 "name": "para" + (n++) + "_imageAddress", "desc": "", //para描述 "relativeXpath": ndPath, "exampleValues": [{ "num": 0, "value": nd.getAttribute("src") == null ? "" : $(nd).prop("src") }] }); } else if (nd.tagName == "A") { //如果element是超链接 outputParameters.push({ "nodeType": 1, "contentType": 0, // 内容类型 "relative": false, //是否为相对xpath路径 "name": "para" + (n++) + "_linktext", "desc": "", //para描述 "relativeXpath": ndPath, "exampleValues": [{ "num": 0, "value": ndText }] }); outputParameters.push({ "nodeType": 2, "contentType": 0, // 内容类型 "relative": false, //是否为相对xpath路径 "name": "para" + (n++) + "_linkAddress", "desc": "", //para描述 "relativeXpath": ndPath, "exampleValues": [{ "num": 0, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") }] }); } else if (nd.tagName == "INPUT") { //如果element是输入项 outputParameters.push({ "nodeType": 3, "contentType": 0, // 内容类型 "relative": false, //是否为相对xpath路径 "name": "para" + (n++) + "_text", "desc": "", //para描述 "relativeXpath": ndPath, "exampleValues": [{ "num": 0, "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value") }] }); } else { //其他所有情况 outputParameters.push({ "nodeType": 0, "contentType": 0, // 内容类型 "relative": false, //是否为相对xpath路径 "name": "para" + (n++) + "_text", "desc": "", //para描述 "relativeXpath": ndPath, "exampleValues": [{ "num": 0, "value": ndText }] }); } } // console.log(outputParameters); let at2 = parseInt(new Date().getTime()); console.log("generateMultiParameters", at2, at, at2 - at); generateValTable(false); }); } //处理子element,对于每个块中多出的特殊element, 需要特殊处理 function handleDescendents() { let n = 1; chrome.storage.local.get({ parameterNum: 1 }, function(items) { let at = parseInt(new Date().getTime()); n = items.parameterNum; clearParameters(); //清除原来的para列表 app._data.selectedDescendents = true; for (let num = 0; num < nodeList.length; num++) { let tnode = nodeList[num]["node"]; let stack = new Array(); //深度优先搜索遍历element stack.push(tnode); //从此节点开始 while (stack.length > 0) { let nd = stack.pop(); // 挨个取出element if (nd.parentNode.tagName == "A" && nd.tagName == "SPAN") { continue; //对A标签内的SPANelement不进行处理,剪枝, 此时子element根本不加入stack, 即实现了此功能 } ndPath = readXPath(nd, 1, tnode); let index = -1; for (let i = 0; i < outputParameters.length; i++) { if (outputParameters[i]["relativeXpath"] == ndPath) { index = i; break; } } outputParameterNodes.push({ "node": nd, "boxShadow": nd.style.boxShadow == "" || boxShadowColor ? "none" : nd.style.boxShadow }); nd.style.boxShadow = boxShadowColor; ndText = $(nd).contents().filter(function() { return this.nodeType === 3; }).text().replace(/\s+/g, ''); if (index == -1) { //从第二个节点开始, 只插入那些不在para列表中的element, 根据xpath进行寻址 //如果当前节点除了子element外仍然有其他文字或者该element是Image/表单项, 加入子element节点 if (ndText != "" || nd.tagName == "IMG" || nd.tagName == "INPUT" || nd.tagName == "A") { if (nd.tagName == "IMG") { //如果element是Image outputParameters.push({ "nodeType": 4, //节点类型 "contentType": 1, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径,注意当只selection了子element没有Select All的时候, 需要判断 "name": "para" + (n++) + "_imageAddress", "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd), //同理需要判断 "exampleValues": [{ "num": num, "value": nd.getAttribute("src") == null ? "" : $(nd).prop("src") }] }); } else if (nd.tagName == "A") { //如果element是超链接 outputParameters.push({ "nodeType": 1, "contentType": 0, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径 "name": "para" + (n++) + "_linktext", "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd), "exampleValues": [{ "num": num, "value": $(nd).text() }] //注意这里的ndtext是整个a的文字!!! }); outputParameters.push({ "nodeType": 2, "contentType": 0, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径 "name": "para" + (n++) + "_linkAddress", "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd), "exampleValues": [{ "num": num, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") }] }); } else if (nd.tagName == "INPUT") { //如果element是输入项 outputParameters.push({ "nodeType": 3, "contentType": 1, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径 "name": "para" + (n++) + "_text", "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd), "exampleValues": [{ "num": num, "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value") }] }); } else { //其他所有情况 outputParameters.push({ "nodeType": 0, "contentType": 1, // 内容类型 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径 "name": "para" + (n++) + "_text", "desc": "", //para描述 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd), "exampleValues": [{ "num": num, "value": ndText }] }); } } } else //如果element节点Already 经存在, 则只需要插入值就可以了 { if (nd.tagName == "IMG") { //如果element是Image outputParameters[index]["exampleValues"].push({ "num": num, "value": nd.getAttribute("src") == null ? "" : $(nd).prop("src") }); } else if (nd.tagName == "A") { //如果element是超链接 outputParameters[index]["exampleValues"].push({ "num": num, "value": $(nd).text() }); outputParameters[index + 1]["exampleValues"].push({ "num": num, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") }); } else if (nd.tagName == "INPUT") { //如果element是输入项 outputParameters[index]["exampleValues"].push({ "num": num, "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value") }); } else { //其他所有情况 outputParameters[index]["exampleValues"].push({ "num": num, "value": ndText }); } } for (let i = nd.children.length - 1; i >= 0; i--) { stack.push(nd.children[i]); } } } let at2 = parseInt(new Date().getTime()); console.log("Select child elements", at2, at, at2 - at); generateValTable(); }); } //根据para列表生成可视化para界面 function generateValTable(multiline = true) { let paravalues = []; for (let i = 0; i < outputParameters.length; i++) { let tvalues = []; let tindex = 0; let l = multiline ? nodeList.length : 1; for (let j = 0; j < l; j++) { //注意第一个循环条件, index超出界限了就不需要再寻找了, 其他的全是空 if (tindex < outputParameters[i]["exampleValues"].length && outputParameters[i]["exampleValues"][tindex]["num"] == j) { tvalues.push(outputParameters[i]["exampleValues"][tindex]["value"]); tindex++; } else { tvalues.push(" "); } } paravalues.push(tvalues); } app._data.valTable = paravalues; } // 选中第一个节点, 自动寻找同类节点 // 方法:/div[1]/div[2]/div[2]/a[1] // 从倒数第一个节点开始找, 看去掉方括号之后是否element数目变多, 如上面的变成/div[1]/div[2]/div[2]/a // 如果没有, 则恢复原状, 然后试试倒数第二个:/div[1]/div[2]/div/a[1] // 直到找到第一个变多的节点或者追溯到根节点为止 function findRelated() { let at = parseInt(new Date().getTime()); let testPath = nodeList[0]["xpath"].split("/").splice(1); //分离xpath成 ["html","body","div[0]"]这样子 let nodeNameList = []; let nodeIndexList = []; for (i = 0; i < testPath.length; i++) { nodeNameList.push(testPath[i].split("[")[0]); if (testPath[i].indexOf("[") >= 0) { //如果存在索引值 nodeIndexList.push(parseInt(testPath[i].split("[")[1].replace("]", ""))); //只留下数字 } else { nodeIndexList.push(-1); } } var tempPath = ""; for (let i = nodeIndexList.length - 1; i >= 0; i--) { if (nodeIndexList[i] == -1) { //没有索引值直接跳过 continue; } tempIndexList = [...nodeIndexList]; //复刻一个index数组 tempIndexList[i] = -1; //删除索引值 tempPath = combineXpath(nodeNameList, tempIndexList); //生成新的xpath var result = document.evaluate(tempPath, document, null, XPathResult.ANY_TYPE, null); result.iterateNext(); //枚举第一个element if (result.iterateNext() != null) { //如果能枚举到第二个element, 说明存在同类element,选中同类element, 结束循环 app.$data.nowPath = tempPath; //标记此elementxpath pushToReadyList(tempPath); break; } } let at2 = parseInt(new Date().getTime()); console.log("findRelated:", at2, at, at2 - at); } //根据path将element放入readylist中 function pushToReadyList(path) { result = document.evaluate(path, document, null, XPathResult.ANY_TYPE, null); var node = result.iterateNext(); //枚举第一个element while (node) { //只添加不在Already 选中列表内的element let exist = false; for (o of nodeList) { if (o["node"] == node) { exist = true; break; } } if (!exist) { readyList.push({ "node": node, "bgColor": node.style.backgroundColor, "boxShadow": node.style.boxShadow == "" || boxShadowColor ? "none" : node.style.boxShadow }); } node.style.boxShadow = boxShadowColor; node = result.iterateNext(); //枚举下一个element } } //将readyList中的element放入选中节点中 function readyToList(step, dealparameters = true) { for (o of readyList) { nodeList.push({ node: o["node"], "step": step, bgColor: o["bgColor"], "boxShadow": o["boxShadow"], xpath: readXPath(o["node"], 1) }); o["node"].style.backgroundColor = selectedColor; } clearReady(); if (dealparameters) { //防止出现先Select child elements再Select All失效的问题 generateParameters(0); //根据nodelist列表内的element生成para列表, 0代表纯text } } //根据节点列表和索引列表生成XPATH // 如:["html","body","div"],[-1,-1,2],生成/html/body/div[2] function combineXpath(nameList, indexList) { let finalPath = ""; for (i = 0; i < nameList.length; i++) { finalPath = finalPath + "/" + nameList[i]; if (indexList[i] != -1) { finalPath = finalPath + "[" + indexList[i] + "]"; } } return finalPath; } //专门测试Already 经选中的这些element之间有没有相关性 // 举例: // /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div[1]/div[3]/a[22] // /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div[2]/div[3]/a[25] // 最终转换为: // /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div/div[3]/a function relatedTest() { let at = new Date().getTime() var testList = []; var testpath = ""; for (i = 0; i < nodeList.length; i++) { var testnumList = []; //用于比较节点索引号不同 var tpath = nodeList[i]["xpath"].split("/").splice(1); //清理第一个空element for (j = 0; j < tpath.length; j++) { if (tpath[j].indexOf("[") >= 0) { //如果存在索引值 testnumList.push(parseInt(tpath[j].split("[")[1].replace("]", ""))); //只留下数字 } else { testnumList.push(-1); } tpath[j] = tpath[j].split("[")[0]; } tp = tpath.join("/"); if (i > 0 && testpath != tp) { //如果去除括号后element内存在不一致情况, 直接返回默认情况代码100 app.$data.nowPath = ""; //标记此elementxpath return 100; } testpath = tp; testList.push(testnumList); } testpath = testpath.split("/"); //清理第一个空element var indexList = []; //记录新生成的xpath //如果选中的element属于同样的序列, 则计算出序列的最佳xpath表达式 for (j = 0; j < testList[0].length; j++) { indexList.push(testList[0][j]); for (i = 1; i < testList.length; i++) { if (testList[i][j] != testList[i - 1][j]) { indexList[j] = -1; //不一致就记录成-1 break; } } } var finalPath = combineXpath(testpath, indexList); app.$data.nowPath = finalPath; //标记此elementxpath pushToReadyList(finalPath); let at2 = parseInt(new Date().getTime()); console.log("手动:", at2, at, at2 - at); return 50; //先返回给默认码 } //实现提示 box拖拽功能 $('.tooldrag').mousedown(function(e) { // e.pageX var positionDiv = $(this).offset(); var distanceX = e.pageX - positionDiv.left; var distanceY = e.pageY - positionDiv.top; //alert(distanceX) // alert(positionDiv.left); $(document).mousemove(function(e) { var x = e.clientX - distanceX; var y = e.clientY - distanceY; if (x < 0) { x = 0; } else if (x > window.innerWidth - $('.tooldrag').outerWidth(true)) { x = window.innerWidth - $('.tooldrag').outerWidth(true); } if (y < 0) { y = 0; } else if (y > window.innerHeight - $('.tooldrag').outerHeight(true)) { y = window.innerHeight - $('.tooldrag').outerHeight(true); } $('.tooltips').css({ 'right': window.innerWidth - x - $('.tooltips').outerWidth(true) + 'px', 'bottom': window.innerHeight - y - $('.tooltips').outerHeight(true) + 'px', }); }); $(document).mouseup(function() { $(document).off('mousemove'); }); });