javascript 获取鼠标相对于元素内容区域的位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5755312/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 18:13:54  来源:igfitidea点击:

getting mouse position relative to content area of an element

javascripthtml

提问by Delan Azabani

When the mouse is moved over an element, I want to get the mouse coordinates of the cursor relative to the top-left of the element's content area (this is the area excluding padding, border and outline). Sounds simple, right? What I have so far is a very popular function:

当鼠标移到一个元素上时,我想获取光标相对于元素内容区域左上角的鼠标坐标(这是不包括填充、边框和轮廓的区域)。听起来很简单,对吧?到目前为止,我拥有的是一个非常受欢迎的功能:

function element_position(e) {
    var x = 0, y = 0;
    do {
        x += e.offsetLeft;
        y += e.offsetTop;
    } while (e = e.offsetParent);
    return { x: x, y: y };
}

And I'd get the mouse position relative to an element elementwith:

我将获得相对于元素的鼠标位置element

p = element_position(element);
x = mouseEvent.pageX - p.x;
y = mouseEvent.pageY - p.y;

That isn't quite correct. Because the offsetLeftand offsetTopare the differences between the 'outer' top left of an element and the 'inner' top left of its offset parent, the sum position will skip over allborders and paddings in the hierarchy.

这不太正确。因为offsetLeftoffsetTop是元素的“外部”左上角与其偏移父项的“内部”左上角之间的差异,因此总和位置将跳过层次结构中的所有边框和填充。

Here's a comparison that should (hopefully) clarify what I mean.

这是一个应该(希望)澄清我的意思的比较。

  • If I get the sum of the distances in position between the 'outer' top left of the elements and the 'inner' top left of their offset parents (outers minus inners; what I am doing right now), I get the element's content area's position, minus all the borders and paddings in the offset hierarchy.
  • If I get the sum of the distances in position between the 'outer' top left of the elements and the 'outer' top left of their offset parents (outers minus outers), I get the element's content area's position, minus the border and padding of the desired element (close, but not quite there).
  • If I get the sum of the distances in position between the 'inner' top left of the elements and the 'inner' top left of their offset parents (inners minus inners), I get the element's content area's position. This is what I want.
  • 如果我得到元素的“外部”左上角与其偏移父项的“内部”左上角之间的距离总和(外部减去内部;我现在在做什么),我得到元素的内容区域位置,减去偏移层次结构中的所有边框和填充。
  • 如果我得到元素的“外部”左上角与其偏移父项的“外部”左上角之间的距离总和(外部减去外部),我得到元素的内容区域的位置,减去边框和填充所需元素的(接近,但不完全存在)。
  • 如果我得到元素的“内部”左上角与其偏移父项的“内部”左上角(内部减去内部)之间的位置距离总和,我将得到元素的内容区域的位置。这就是我要的。

采纳答案by brainjam

Here's a live example that uses an element_position()function that is aware of padding and borders. I've added some extra padding and margins to your original example.

这是一个使用element_position()可识别填充和边框的函数的现场示例。我在您的原始示例中添加了一些额外的填充和边距。

http://jsfiddle.net/Skz8g/4/

http://jsfiddle.net/Skz8g/4/

To use it, move the cursor over the brown area. The resulting white area is the actual canvas content. The brown is padding, the red is a border, and so on. In both this example and the one later on, the canvas xand canvas yreadouts indicate the cursor position relative to canvas content.

要使用它,请将光标移到棕色区域上。生成的白色区域是实际的画布内容。棕色是填充,红色是边框,依此类推。在本示例和后面的示例中,canvas xcanvas y读数指示相对于画布内容的光标位置。

Here's the code for element_position():

这是代码element_position()

function getNumericStyleProperty(style, prop){
    return parseInt(style.getPropertyValue(prop),10) ;
}

function element_position(e) {
    var x = 0, y = 0;
    var inner = true ;
    do {
        x += e.offsetLeft;
        y += e.offsetTop;
        var style = getComputedStyle(e,null) ;
        var borderTop = getNumericStyleProperty(style,"border-top-width") ;
        var borderLeft = getNumericStyleProperty(style,"border-left-width") ;
        y += borderTop ;
        x += borderLeft ;
        if (inner){
          var paddingTop = getNumericStyleProperty(style,"padding-top") ;
          var paddingLeft = getNumericStyleProperty(style,"padding-left") ;
          y += paddingTop ;
          x += paddingLeft ;
        }
        inner = false ;
    } while (e = e.offsetParent);
    return { x: x, y: y };
}

The code should work properly in IE9, FF and Chrome, although I notice it is not quite right in Opera.

代码在 IE9、FF 和 Chrome 中应该可以正常工作,尽管我注意到它在 Opera 中不太正确。

My original inclination was to use something like the e.offsetX/Yproperties because they were closer to what you want, and do not involve looping over nested elements. However, their behaviour varies wildly across browsers, so a bit of cross-browser finagling is necessary. The live example is here:

我最初的倾向是使用类似e.offsetX/Y属性的东西,因为它们更接近你想要的,并且不涉及嵌套元素的循环。然而,它们的行为因浏览器而异,因此需要进行一些跨浏览器的调整。现场示例在这里:

http://jsfiddle.net/xUZAa/6/

http://jsfiddle.net/xUZAa/6/

It should work across all modern browsers - Opera, FF, Chrome, IE9. I personally prefer it, but thought that although your original question was just about "getting mouse position relative to content area of an element", you were really asking about how to make the element_position()function work correctly.

它应该适用于所有现代浏览器 - Opera、FF、Chrome、IE9。我个人更喜欢它,但认为尽管您最初的问题只是关于“获取相对于元素内容区域的鼠标位置”,但您实际上是在询问如何使该element_position()功能正常工作。

回答by Mark Kahn

using jQuery:

使用jQuery:

function posRelativeToElement(elem, ev){
    var $elem = $(elem),
         ePos = $elem.offset(),
     mousePos = {x: ev.pageX, y: ev.pageY};

    mousePos.x -= ePos.left + parseInt($elem.css('paddingLeft')) + parseInt($elem.css('borderLeftWidth'));
    mousePos.y -= ePos.top + parseInt($elem.css('paddingTop')) + parseInt($elem.css('borderTopWidth'));

    return mousePos;
};

live example: http://jsfiddle.net/vGKM3/

现场示例:http: //jsfiddle.net/vGKM3/

The root of this is simple: compute the element's position relative to the document. I then drop the top & left padding & border (margin is included with basic positioning calculations). The internal jQuery code for doing this is based on getComputedStyleand element.currentStyle. Unfortunately I don't think there is another way...

其根源很简单:计算元素相对于文档的位置。然后我删除顶部和左侧的填充和边框(边距包含在基本定位计算中)。执行此操作的内部 jQuery 代码基于getComputedStyleelement.currentStyle。不幸的是,我认为没有其他方法......

The core of jQuery's .offset()function, which gets an element's position relative to document:

jQuery.offset()函数的核心,它获取元素相对于文档的位置:

if ( "getBoundingClientRect" in document.documentElement ) {
    ...
    try {
        box = elem.getBoundingClientRect();
    } catch(e) {}

    var body = doc.body,
        win = getWindow(doc),
        clientTop  = docElem.clientTop  || body.clientTop  || 0,
        clientLeft = docElem.clientLeft || body.clientLeft || 0,
        scrollTop  = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop ),
        scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft),
        top  = box.top  + scrollTop  - clientTop,
        left = box.left + scrollLeft - clientLeft;

    return { top: top, left: left };
}else{
    // calculate recursively based on .parentNode and computed styles
}

Theoretically, another way to do this would be, using the above positioning code:

理论上,另一种方法是使用上面的定位代码:

  • make sure your element has position: relative(or absolute) set
  • append a new element with position: absolute; top:0px; left:0px;
  • get the position of the newelement relative to the document. It will be the same as the content position of the parent
  • delete the new element
  • 确保您的元素具有position: relative(或绝对)设置
  • 附加一个新元素 position: absolute; top:0px; left:0px;
  • 获取元素相对于文档的位置。它将与父级的内容位置相同
  • 删除新元素

回答by Aleadam

In your element_position(e)function, iterate through the hierarchy using parentNode, get the padding, offsets and border using getComputedStyle(e, null).getPropertyValue(each_css), and sum them to the value of your xand yvalues before return.

在您的element_position(e)函数中,使用 迭代层次结构,使用parentNode获取填充、偏移和边框getComputedStyle(e, null).getPropertyValue(each_css),并在返回之前将它们与您的值xy值相加。

There's a post proposing a cross-browser reading of styles here:

这里有一篇文章提出了跨浏览器阅读样式的建议:

http://bytes.com/topic/javascript/answers/796275-get-div-padding

http://bytes.com/topic/javascript/answers/796275-get-div-padding

回答by David Houde

I am not sure if this is the best way, or most resource efficient...

我不确定这是否是最好的方法,还是最有效的资源...

But I would suggest getting X/Y for the canvas tag, width of the border, and padding and using them all together as the offset.

但我建议为画布标签、边框宽度和填充获取 X/Y,并将它们一起用作偏移量。

Edit:

编辑:

Use offsetLeft and offsetTop

使用 offsetLeft 和 offsetTop

Reference: How to Use the Canvas and Draw Elements in HTML5

参考:如何在 HTML5 中使用 Canvas 和绘制元素

var x;
var y;
if (e.pageX || e.pageY) { 
  x = e.pageX;
  y = e.pageY;
}
else { 
  x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 
  y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 
} 
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;