简写:
我想在纯JavaScript中模仿Google Chrome的Inspect Element工具。
长版本:
我正在为谷歌浏览器的扩展工作。我想在纯JavaScript 中实现类似于Inspect Element工具的东西(没有jQuery或任何其他库/框架/依赖项)。如果有人使用AdBlock,我特别想模仿"在此页面上阻止广告"。允许用户在页面上选择一个元素的功能。
当扩展处于活动状态时,用户应该能够:
- 鼠标悬停在元素上
- 如果一个带有
'CODE' element nested inside
的"P"元素被鼠标悬停,整个"P"元素应该有"DIV"覆盖在它上面 - 如果鼠标移动到嵌套的
'CODE' element
上,它应该重新调整'DIV'覆盖的大小,以覆盖仅更深嵌套的'CODE' element
- 当点击时,底层元素应该被存储,'DIV'覆盖隐藏
为什么使用'DIV'覆盖,而不是只是添加一个类的元素,添加边框/轮廓/背景色?
覆盖层阻止用户直接与元素交互。如果有一个href/onClick属性,我不希望它在点击时激活。
你能不能写一些东西来存储所有内联的'onclick'属性,将它们设置为null/返回false;然后恢复原来的'onclick'代码?
试过:
onclicks = document.querySelectorAll('[onclick]');
saved = [];
// disable onclicks
function disableOnclicks() {
for (var i = 0; i < onclicks.length; i++) {
saved[i] = onclicks[i].cloneNode();
onclicks[i].onclick = "return false;";
};
console.log("onclicks disabled");
}
// enable onclicks
function enableOnclicks() {
for (var i = 0; i < onclicks.length; i++) {
onclicks[i].onclick = saved[i].onclick;
};
console.log("onclicks enabled");
}
// if injecting script, make sure all elements have loaded
window.onload = function(){
disableOnclicks();
console.log("onclicks disabled");
enableOnclicks();
console.log("onclicks enabled");
}
不幸的是,它不能处理给定页面上的任何不可见事件侦听器。
我的当前代码格式化粘贴到控制台:
// CSS to highlight element
var overlayCSS = document.createElement("style");
overlayCSS.type = "text/css";
overlayCSS.innerHTML = "body .highlight-element{z-index:2147483647!important}.highlight-element{background-color:rgba(130,180,230,.4);outline:#0F4D9A solid 1px;box-sizing:border-box;position:absolute;display:none}";
document.body.appendChild(overlayCSS); // append style tag to body
// create div overlay to highlight elements & prevent onclick events
var overlay = document.createElement("div");
overlay.className = "highlight-element";
document.body.appendChild(overlay); // append div overlay to body
// check if overlay was appended
if (overlay === document.getElementsByClassName('highlight-element')[0]) {
console.log("overlay exists");
};
// positions div overlay based on targetRect AKA element.getBoundingClientRect()
function moveOverlay (targetRect) {
var overlay = document.getElementsByClassName('highlight-element')[0];
// correct for page scroll
overlay.style.top = (targetRect.top + window.scrollY) + "px";
overlay.style.left = targetRect.left + "px";
overlay.style.height = targetRect.height + "px";
overlay.style.width = targetRect.width + "px";
overlay.style.display = "block";
}
// set start time for lastfire
var lastfire = Date.now();
function getInnermostHovered(e) {
// difference between now and the last event
var difference = Date.now() - lastfire;
// console.log(difference);
// delay handling mousemove by some milliseconds
// making 0 may induce epileptic shock...
if (difference > 100) {
// prevent endless highlight loop
if (e.target.getAttribute('class') == "highlight-element") {
e.target.style.display = "none";
}
// get element under mouse
var n = document.querySelector(":hover");
var nn;
// get deepest child element that has :hover
while (n) {
nn = n;
n = nn.querySelector(":hover");
}
console.log("nn: " + nn);
// get dimensions to pass to div overlay
var targetRect = nn.getBoundingClientRect();
// console.log(targetRect.top);
// display overlay div at element position under mouse
moveOverlay(targetRect);
// event fired, so overwrite last fire time
lastfire = Date.now();
}
}
// onMouseMove get deepest child element under the mouse
document.addEventListener('mousemove', getInnermostHovered, false);
请随意在本页上进行测试(刷新页面以取消),目前我通过在' mousmove '事件上交替显示/隐藏覆盖'DIV'来进行覆盖工作。理想情况下,我希望它运行顺利Chrome的检查元素,并给我的元素数据。任何想法都是值得赞赏的,但我必须强调的是,我真的想用纯JavaScript来做这件事。
用document.elementFromPoint(x,y)
求解
此代码将工作粘贴在Chrome的控制台,按ESC取消。
var rootNode = document.documentElement;
var currentNode = currentNode || {};
var lastNode = lastNode || {};
var nodeClone = nodeClone || {};
var prevOnClick = prevOnClick || {};
function nodeHandler (e) {
var x = e.clientX;
var y = e.clientY;
// console.log(x+", "+y);
currentNode = document.elementFromPoint(x, y);
if (currentNode === rootNode || currentNode === document.body){
// If current node is HTML or BODY, do nothing
} else {
if (currentNode === lastNode) {
// If still on same node, do nothing
// console.log('Same node');
} else {
// console.log('Different node');
// if lastNode has classList, check for onclick attribute and remove highlight-element class
if (lastNode.classList) {
// If lastNode had onclick attribute, replace with the untouched value from nodeClone
if (lastNode.getAttribute("onclick") != null) {
prevOnClick = nodeClone.getAttribute("onclick");
lastNode.setAttribute("onclick", prevOnClick);
}
lastNode.classList.remove('highlight-element');
}
// Save currentNode and preserve any inline event (onclick) attributes
nodeClone = currentNode.cloneNode();
// if currentNode has onclick attribute, disable it
if (currentNode.getAttribute("onclick")) {
currentNode.setAttribute("onclick", "return false;");
};
// Add highlight class to currentNode
currentNode.classList.add('highlight-element');
}
// store node
lastNode = currentNode;
}
}
function clickHandler (e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
console.log("Clicked Node:n");
console.log(nodeClone);
}
function cancelNodeSelect (e) {
if (e.keyCode == 27) {
// if lastNode has classList, check for onclick attribute and remove highlight-element class
if (lastNode.classList) {
if (lastNode.getAttribute("onclick") != null) {
prevOnClick = nodeClone.getAttribute("onclick");
lastNode.setAttribute("onclick", prevOnClick);
}
lastNode.classList.remove('highlight-element');
}
// remove event listeners
document.removeEventListener('click', clickHandler, false);
document.removeEventListener('mousemove', nodeHandler, false);
document.removeEventListener('keyup', cancelNodeSelect, false);
console.log("escape pressed");
};
}
document.addEventListener('click', clickHandler, false);
document.addEventListener('mousemove', nodeHandler, false);
document.addEventListener('keyup', cancelNodeSelect, false);
和css:
.highlight-element {
background-color: rgba(130, 180, 230, 0.4);
outline: solid 1px #0F4D9A;
box-sizing: border-box;
}
这个答案是作为编辑https://stackoverflow.com/revisions/33050714/2和https://stackoverflow.com/revisions/33050714/3发布的问题,当鼠标悬停在纯Javascript中,OP g_let在CC by - sa 3.0下,用Div覆盖突出显示最深的子DOM元素。