Javascript:让用户选择像Firebug这样的HTML元素?
我想编写一个浏览器(Chrome/FF)扩展,它需要在网页上选择一个元素。我希望它像Firebug的元素检查器一样工作。单击“检查”箭头,然后可以悬停/高亮显示图元。单击所需图元时,将检查该图元。我只对允许用户选择元素的代码感兴趣,而不是实际检查它或任何类似的东西Javascript:让用户选择像Firebug这样的HTML元素?,javascript,dom,google-chrome,google-chrome-extension,firebug,Javascript,Dom,Google Chrome,Google Chrome Extension,Firebug,我想编写一个浏览器(Chrome/FF)扩展,它需要在网页上选择一个元素。我希望它像Firebug的元素检查器一样工作。单击“检查”箭头,然后可以悬停/高亮显示图元。单击所需图元时,将检查该图元。我只对允许用户选择元素的代码感兴趣,而不是实际检查它或任何类似的东西 因为我正在编写一个扩展,如果您可以提供非jQuery/Prototype/等,那就太好了。。代码,这样我就不必分发了。我在Firebug小组中询问,并得到了一些很好的帮助: 一种简单的方法是使用轮廓而不是边框: .highlight
因为我正在编写一个扩展,如果您可以提供非jQuery/Prototype/等,那就太好了。。代码,这样我就不必分发了。我在Firebug小组中询问,并得到了一些很好的帮助:
一种简单的方法是使用轮廓而不是边框:
.highlight { outline: 4px solid #07C; }
只需将该类添加到要选择/取消选择的任何元素并将其删除(下面的代码未正确测试):
因为您使用的是轮廓(Chrome支持),而不是边框,所以元素不会四处跳跃。我在我的中使用了类似的东西。在Stackoverflow上有一个类似的问题,它有很多很好的答案: 对于那些正在寻找快速、肮脏解决方案的人: 这是最简单的。只要把代码放在
标签中,就可以开始了
稍微好一点,仍然很容易集成
对于更复杂的元素检查器,您可能需要检查Udi所指出的SelectorGadget。inspector选择代码在中,我使用jQuery作为另一个项目的组件编写了一个实现。源文件和文档可在此处找到:也可以查看此文件: 我觉得这很有见地。。这里有一个演示:
希望这能有所帮助。我最近在一个项目中需要这样一个功能,结果我不得不使用“侧边”来创建一个框,否则当你移动鼠标时,
事件.target
将成为选择器,如果我使用z-index:-1
当有很多元素重叠时,会有点可疑……等等
为了您的利益,我从我的项目中转换了一个版本,它涉及jQuery,但是转换为vanilla非常简单,因为只使用jQuery中的mousemove
&css
方法
一步一步的说明
首先创建所需的5html元素
<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
中,我们将进行一些基本检查,以防止选择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;
}
转换
为选择器提供了非常好的滑动效果
试一试
注:这也适用于变换:比例(2)代码>例如,当元素按比例缩放时
编辑:我刚刚更新了这个,我注意到
元素
对象是在事件处理程序内部的,我在演示中将它移到了外部,这是一个相当重要的性能改进,因为现在,elements
对象只创建了一次,而不是mousemove
事件中的数十万次(如果不是数百万次)。您需要做的是为高亮显示创建4个元素。它们将形成一个空方块,因此您的鼠标事件可以自由触发。这和我做的很像
不同之处在于,您只需要四个元素(不需要调整大小标记),并且四个框的大小和位置略有不同(以模仿红色边框)。然后,您可以在事件处理程序中使用event.target
,因为默认情况下它会获取真正的最顶层元素
另一种方法是隐藏exra元素,从点获取元素,计算后将其放回
我可以告诉你,它们比光速快。甚至爱因斯坦也会同意:)
1.)元素从点覆盖/边框-[]FF需要v3.0+
var-box=$(“”).css({
显示:“无”,位置:“绝对”,
zIndex:65000,背景:“rgba(255,0,0,3)”
}).附于(“主体”);
变量mouseX、mouseY、target、lastTarget;
//如果您需要支持较旧的浏览器,请使用requestAnimationFrame多边形填充
//例如:https://gist.github.com/paulirish/1579671
requestAnimationFrame(函数框(){
window.requestAnimationFrame(帧);
if(target&&target.className==“外部”){
box.hide();
target=document.elementFromPoint(mouseX,mouseY);
}
box.show();
如果(target==lastTarget)返回;
lastTarget=目标;
变量$target=$(目标);
var offset=$target.offset();
box.css({
宽度:$target.outerWidth()-1,
高度:$target.outerHeight()-1,
左:offset.left,
顶部:offset.top
});
});
$(“body”).mousemove(函数(e){
mouseX=e.clientX;
穆西=e.clientY;
target=e.target;
});
2.)鼠标越过边框-[]
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);
}
var-box=newoverlay();
$(“body”).mouseover(函数(e){
var el=$(e.target);
var offset=el.offset();
渲染(el.outerWidth(),el.outerHeight(),offset.left,offset.top);
});
/**
*此对象封装覆盖的元素和操作。
*/
功能叠加(宽度、高度、左侧、顶部){
this.width=this.he
#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;
}
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;
});
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);
}
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");
}
}
.hovered,
.hovered * {
cursor: pointer;
color: black;
background-color: red;
}
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;
}
});
// 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);
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";
});