41

我想编写一个浏览器(Chrome/FF)扩展,需要在网页上选择一个元素。我希望它表现得像 Firebug 的元素检查器那样。单击检查箭头,然后可以悬停/突出显示元素。当您单击所需的元素时,将检查该元素。我只是对允许用户选择一个元素的代码感兴趣——而不是实际检查它或任何类似的东西。

因为我正在编写一个扩展,如果你能提供非 jQuery/Prototype/etc.. 代码可能会很好,所以我不必分发它。

4

10 回答 10

25

我最近在我正在处理的一个项目中需要这样一个功能,结果我不得不使用 for 边来创建一个框,因为否则event.target当你移动鼠标时最终会成为选择器,如果我要使用z-index: -1它当你有很多重叠的元素时会有点可疑......等等。

这是我为您的利益从我的项目中转换的版本,它涉及 jQuery,但转换为vanilla非常简单,因为仅使用 jQuery 中的mousemove&css方法。

一步一步的指示。

首先创建所需的5 个HTMLElement。

<div id="selector">
    <div id="selector-top"></div>
    <div id="selector-left"></div>
    <div id="selector-right"></div>
    <div id="selector-bottom"></div>
</div>

其次在(或您的容器)上创建一个mousemove事件document

$(document).mousemove(function(event) { ... });

然后在里面mousemove我们会做一些基本的检查来防止选择HTML, BODY, selector

var id = event.target.id, tagName = event.target.tagName;

if(id.indexOf('selector') !== -1 || tagName === 'BODY' || tagName === 'HTML') {
   return;
} 

然后我们需要创建一个对象来像这样存储我们的元素。

var elements = {
    top: $('#selector-top'),
    left: $('#selector-left'),
    right: $('#selector-right'),
    bottom: $('#selector-bottom')
};

之后,我们存储一些变量,这些变量保存了一些关于目标元素的信息,就像这样。

var $target = event.target;
    targetOffset = $target.getBoundingClientRect(),
    targetHeight = targetOffset.height,
    targetWidth  = targetOffset.width;

然后我们所做的就是像这样计算选择器所有4 个边的位置高度。

elements.top.css({
    left:  (targetOffset.left - 4),
    top:   (targetOffset.top - 4),
    width: (targetWidth + 5)
});

elements.bottom.css({
    top:   (targetOffset.top + targetHeight + 1),
    left:  (targetOffset.left  - 3),
    width: (targetWidth + 4)
});

elements.left.css({
    left:   (targetOffset.left  - 5),
    top:    (targetOffset.top  - 4),
    height: (targetHeight + 8)
});

elements.right.css({
    left:   (targetOffset.left + targetWidth + 1),
    top:    (targetOffset.top  - 4),
    height: (targetHeight + 8)
});

所有这些+aFewPixels都只是一点点优化,因此2px选择器和目标之间存在类似的差距。

因为CSS这就是我想出的。

#selector-top, #selector-bottom {
    background: blue;
    height:3px;
    position: fixed;
    transition:all 300ms ease;
}

#selector-left, #selector-right {
    background: blue;
    width:3px;
    position: fixed;
    transition:all 300ms ease;
}

transition选择器一个非常好的滑动效果。

试用演示http://jsfiddle.net/rFc8E/9/

注意:这也适用于transform: scale(2);例如。当一个元素的大小被缩放时。

编辑:我刚刚更新了这个,我注意到elements对象事件处理程序中,我在演示中将它移到外面,这是一个非常重要的性能改进,因为现在,elements对象只创建一次而不是数百个在事件中成千上万次,甚至数百万次。mousemove

于 2013-09-07T16:26:31.140 回答
20

我使用 jQuery 作为另一个项目的组件编写了一个实现。源代码和文档可在此处获得:https ://github.com/andrewchilds/jQuery.DomOutline

于 2012-10-20T23:11:12.193 回答
14

一种简单的方法是使用轮廓而不是边框​​:

.highlight { outline: 4px solid #07C; }

只需将该类添加和删除到您要选择/取消选择的任何元素(下面的代码未正确测试):

document.body.addEventListener("mouseover", function(e) {
    e.stopPropagation();
    e.target.addEventListener("mouseout", function (e) {
        e.target.className = e.target.className.replace(new RegExp(" highlight\\b", "g"), "");
    });
    e.target.className += " highlight";
});

由于您使用的是轮廓(Chrome 支持)而不是边框​​,因此元素不会跳来跳去。我在我的EasyReader Extension中使用了类似的东西。

于 2010-08-30T10:44:07.487 回答
11

HTML 元素选择器 (Vanilla JS)

仅使用 Vanilla JS 选择并突出显示页面上的任何 HTML 元素!在 Chrome、FF 和 Opera 中测试,在 IE 中不起作用。

这个怎么运作:

你需要的其实很简单。您可以在 JS 中创建一个带有背景的空 div 框,然后移动它以突出显示悬停元素的顶部。这是JS代码:

const hoverBox = document.createElement("div");
console.log("hoverBox: ", hoverBox);
hoverBox.style.position = "absolute";
// change to whatever highlight color you want
hoverBox.style.background = "rgba(153, 235, 255, 0.5)";
// avoid blocking the hovered element and its surroundings
hoverBox.style.zIndex = "0";
document.body.appendChild(hoverBox);
let previousTarget;
document.addEventListener("mousemove", (e) => {
    let target = e.target;
    if (target === hoverBox) {
        // the truely hovered element behind the added hover box
        const hoveredElement = document.elementsFromPoint(e.clientX, e.clientY)[1];
        if (previousTarget === hoveredElement){
            // avoid repeated calculation and rendering
            return;
        } else{
            target = hoveredElement;
        }
    } else{
        previousTarget = target;
    }
    const targetOffset = target.getBoundingClientRect();
    const targetHeight = targetOffset.height;
    const targetWidth = targetOffset.width;
    // add a border around hover box
    const boxBorder = 5;
    hoverBox.style.width = targetWidth + boxBorder * 2 + "px";
    hoverBox.style.height = targetHeight + boxBorder * 2 + "px";
    // need scrollX and scrollY to account for scrolling
    hoverBox.style.top = targetOffset.top + window.scrollY - boxBorder + "px";
    hoverBox.style.left = targetOffset.left + window.scrollX - boxBorder + "px";
});

查看演示
我还为元素选择器制作了一个npm 包,其中包含更多用户配置,如背景颜色、边框宽度、过渡等。这是GitHub 页面

于 2019-04-06T11:49:48.603 回答
7

我最终在 Firebug 小组中询问并得到了一些很大的帮助:

http://groups.google.com/group/firebug/browse_thread/thread/7d4bd89537cd24e7/2c9483d699efe257?hl=en#2c9483d699efe257

于 2010-03-13T16:34:48.407 回答
4

这是一个用纯 javascript 编写的库作为替代方案。

TheRoom JS:https ://github.com/hsynlms/theroomjs

// theroom information template for target element
var template="";
template += "<div id=\"theroom-info\">";
template += "  <span id=\"theroom-tag\"><\/span>";
template += "  <span id=\"theroom-id\"><\/span>";
template += "  <span id=\"theroom-class\"><\/span>";
template += "<\/div>";
template += "";
template += "<style>";
template += "  #theroom-info {";
template += "    position: fixed;";
template += "    bottom: 0;";
template += "    width: 100%;";
template += "    left: 0;";
template += "    font-family: \"Courier\";";
template += "    background-color: #ffffff;";
template += "    padding: 10px;";
template += "    color: #333333;";
template += "    text-align: center;";
template += "    box-shadow: 0px 4px 20px rgba(0,0,0,0.3);";
template += "  }";
template += "";
template += "  #theroom-tag {";
template += "    color: #C2185B;";
template += "  }";
template += "";
template += "  #theroom-id {";
template += "    color: #5D4037;";
template += "  }";
template += "";
template += "  #theroom-class {";
template += "    color: #607D8B;";
template += "  }";
template += "<\/style>";

var options = {
  template: template,
  showInfo: true
};

// initialize
theRoom.start(options);

代码笔演示

于 2018-04-13T22:28:40.960 回答
2

在 Stackoverflow 上有一个类似的问题,它有很多很好的答案: 有人知道 DOM 检查器 javascript 库或插件吗?

对于那些正在寻找快速而肮脏的解决方案的人:

http://userscripts.org/scripts/review/3006是最简单的。只需将代码放在<script></script>标签中即可。

https://github.com/josscrowcroft/Simple-JavaScript-DOM-Inspector/blob/master/inspector.js稍微好一些,并且仍然很容易集成。

对于更复杂的元素检查器,您可能需要查看 Udi 指出的 SelectorGadget。检查器选择代码在http://www.selectorgadget.com/stable/lib/interface.js

于 2011-10-12T15:02:11.070 回答
2

还要检查这个:

http://rockingcode.com/tutorial/element-dom-tree-jquery-plugin-firebug-like-functionality/

我发现它很有见地..这里有一个演示:

http://rockingcode.com/demos/elemtree/

希望这可以帮助。

于 2013-03-20T20:06:00.037 回答
2

一个非常基本的实现可以很容易地在没有 jQuery 的情况下使用.onmouseoverand完成e.target

var last,
    bgc;
document.onmouseover = function(e) {
    var elem = e.target;

    if (last != elem) {
        if (last != null) {
            last.classList.remove("hovered");
        }

        last = elem;
        elem.classList.add("hovered");
    }
}

如果您希望孩子也更改背景,请使用下面的 CSS:

.hovered,
.hovered * {
    cursor: pointer;
    color: black;
    background-color: red;
}

演示


如果您只想选择边缘附近的元素(或选择边缘附近的父元素和其他任何地方的元素本身),您可以使用.getBoundingClientRect.

var last;
window.addEventListener("mousemove", function(e) {
  if(last) {
    last.style.background = ''; // empty is enough to restore previous value
  }
    var elem = e.target;

  if(elem === document.body || elem === document.documentElement) {
    return;
  }
  var bb = elem.getBoundingClientRect();
  var xr = e.pageX - bb.left; // x relative to elem
  var yr = e.pageY - bb.top; // y relative to elem
  var ew = 10; // edge width

  if(
       xr <= ew
    || xr >= bb.width - ew
    || yr <= ew
    || yr >= bb.height - ew
  ){
    elem.style.background = 'red';
    last = elem;
  }
});

搭配一些边框,这对于选择非常有用。演示

于 2016-05-19T17:22:42.993 回答
1

您需要做的是为突出显示创建 4 个元素。它们将形成一个空方格,因此您的鼠标事件可以自由触发。这类似于我制作的这个覆盖示例。

不同之处在于您只需要四个元素(没有调整大小标记),并且 4 个框的大小和位置有点不同(模仿红色边框)。然后你可以event.target在你的事件处理程序中使用,因为它默认获取真正的最顶层元素。

另一种方法是隐藏 exra 元素,获取elementFromPoint,计算然后放回去。

我可以告诉你,它们比光还快。甚至爱因斯坦也会同意:)

1.) elementFromPoint 覆盖/边框 - [ Demo1 ] FF 需要 v3.0+

var box = $("<div class='outer' />").css({
  display: "none", position: "absolute", 
  zIndex: 65000, background:"rgba(255, 0, 0, .3)"
}).appendTo("body");

var mouseX, mouseY, target, lastTarget;

// in case you need to support older browsers use a requestAnimationFrame polyfill
// e.g: https://gist.github.com/paulirish/1579671
window.requestAnimationFrame(function frame() {
  window.requestAnimationFrame(frame);
    if (target && target.className === "outer") {
        box.hide();
        target = document.elementFromPoint(mouseX, mouseY);
    }
    box.show();   

    if (target === lastTarget) return;

    lastTarget = target;
    var $target = $(target);
    var offset = $target.offset();
    box.css({
        width:  $target.outerWidth()  - 1, 
        height: $target.outerHeight() - 1, 
        left:   offset.left, 
        top:    offset.top 
    });
});

$("body").mousemove(function (e) {
    mouseX = e.clientX;
    mouseY = e.clientY;
    target = e.target;
});

2.) 鼠标悬停边框 - [ Demo2 ]

var box = new Overlay();

$("body").mouseover(function(e){
  var el = $(e.target);
  var offset = el.offset();
  box.render(el.outerWidth(), el.outerHeight(), offset.left, offset.top);
});​

/**
 * This object encapsulates the elements and actions of the overlay.
 */
function Overlay(width, height, left, top) {

    this.width = this.height = this.left = this.top = 0;

    // outer parent
    var outer = $("<div class='outer' />").appendTo("body");

    // red lines (boxes)
    var topbox    = $("<div />").css("height", 1).appendTo(outer);
    var bottombox = $("<div />").css("height", 1).appendTo(outer);  
    var leftbox   = $("<div />").css("width",  1).appendTo(outer);
    var rightbox  = $("<div />").css("width",  1).appendTo(outer);

    // don't count it as a real element
    outer.mouseover(function(){ 
        outer.hide(); 
    });    

    /**
     * Public interface
     */

    this.resize = function resize(width, height, left, top) {
      if (width != null)
        this.width = width;
      if (height != null)
        this.height = height;
      if (left != null)
        this.left = left;
      if (top != null)
        this.top = top;      
    };

    this.show = function show() {
       outer.show();
    };

    this.hide = function hide() {
       outer.hide();
    };     

    this.render = function render(width, height, left, top) {

        this.resize(width, height, left, top);

        topbox.css({
          top:   this.top,
          left:  this.left,
          width: this.width
        });
        bottombox.css({
          top:   this.top + this.height - 1,
          left:  this.left,
          width: this.width
        });
        leftbox.css({
          top:    this.top, 
          left:   this.left, 
          height: this.height
        });
        rightbox.css({
          top:    this.top, 
          left:   this.left + this.width - 1, 
          height: this.height  
        });

        this.show();
    };      

    // initial rendering [optional]
    // this.render(width, height, left, top);
}
于 2015-05-31T08:15:33.387 回答