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

时间:2011-04-22 12:17:08

标签: javascript html

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

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 };
}

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

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

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

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

  • 如果我得到元素的“外部”左上角和偏移父母的“内部”左上角之间的距离总和( outers减去内部;我正在做什么现在,我得到元素的内容区域的位置,减去偏移层次结构中的所有边框和填充。
  • 如果我得到元素的“外部”左上角和偏移父母的“外部”左上角之间的距离总和( outers减去outers ),我得到了元素的内容区域的位置,减去所需元素的边框和填充(关闭,但不完全存在)。
  • 如果我得到元素的“内部”左上角和偏移父母的“内部”左上角之间的距离总和(内部减去内部),我得到了元素的内容区域的位置。这就是我想要的。

4 个答案:

答案 0 :(得分:10)

这是一个使用element_position()函数的实时示例,该函数知道填充和边框。我在原始示例中添加了一些额外的填充和边距。

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

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

以下是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 };
}

代码应该在IE9,FF和Chrome中正常运行,虽然我注意到它在Opera中不太正确。

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

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

它应该适用于所有现代浏览器 - Opera,FF,Chrome,IE9。我个人更喜欢它,但认为虽然你的原始问题只是“相对于元素的内容区域获得鼠标位置”,但你真的在询问如何使element_position()函数正常工作。

答案 1 :(得分:4)

使用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;
};

直播示例:http://jsfiddle.net/vGKM3/

这个的根本很简单:计算元素相对于文档的位置。然后我放弃顶部&左边填充&am​​p;边界(边距包含在基本定位计算中)。执行此操作的内部jQuery代码基于getComputedStyleelement.currentStyle。不幸的是,我认为还有另一种方式...

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
}

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

  • 确保您的元素设置为position: relative(或绝对值)
  • 使用position: absolute; top:0px; left:0px;
  • 附加新元素
  • 获取 new 元素相对于文档的位置。它将与父
  • 的内容位置相同
  • 删除新元素

答案 2 :(得分:2)

element_position(e)函数中,使用parentNode遍历层次结构,使用getComputedStyle(e, null).getPropertyValue(each_css)获取填充,偏移和边框,并将它们与x的值相加返回前的y值。

这里有一篇帖子建议跨浏览器阅读样式:

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

答案 3 :(得分:1)

我不确定这是最好的方式,还是资源效率最高的......

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

编辑:

使用offsetLeft和offsetTop

参考:How to Use the Canvas and Draw Elements in HTML5

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;