查找鼠标相对于元素的位置

IT技术 javascript
2021-02-05 19:19:45

我想使用画布制作一个小绘画应用程序。所以我需要在画布上找到鼠标的位置。

6个回答

由于我没有找到可以复制/粘贴的无 jQuery 答案,这是我使用的解决方案:

document.getElementById('clickme').onclick = function clickEvent(e) {
      // e = Mouse click event.
      var rect = e.target.getBoundingClientRect();
      var x = e.clientX - rect.left; //x position within the element.
      var y = e.clientY - rect.top;  //y position within the element.
      console.log("Left? : " + x + " ; Top? : " + y + ".");
    }
#clickme {
  margin-top: 20px;
  margin-left: 100px;
  border: 1px solid black;
  cursor: pointer;
}
<div id="clickme">Click Me -<br>
(this box has margin-left: 100px; margin-top: 20px;)</div>

完整示例的 JSFiddle

PSA:@mpen 的评论已过时;这种方法确实有效,即使在滚动的情况下也是如此。查看他们 Fiddle 的更新版本:jsfiddle.net/6wcsovp2
2021-03-21 19:19:45
新编辑应该修复滚动问题(使用 clientX/Y)
2021-03-25 19:19:45
谢谢!一个注意事项:您需要的是e.currentTarget,而不是 e.target。否则子元素会影响它
2021-03-30 19:19:45
您需要使用此方法对边界矩形进行四舍五入以确保整数值。
2021-04-03 19:19:45
这个答案应该被投票赞成。谢谢任何时候coder 和@ErikKoopmans。
2021-04-04 19:19:45

对于使用 JQuery 的人:

有时,当您有嵌套元素时,其中一个元素附加了事件,理解浏览器将什么视为父元素可能会令人困惑。在这里,您可以指定哪个父级。

您获取鼠标位置,然后从父元素的偏移位置中减去它。

var x = evt.pageX - $('#element').offset().left;
var y = evt.pageY - $('#element').offset().top;

如果您尝试在滚动窗格内的页面上获取鼠标位置:

var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop();

或者相对于页面的位置:

var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft();
var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();

请注意以下性能优化:

var offset = $('#element').offset();
// Then refer to 
var x = evt.pageX - offset.left;

这样,JQuery 就不用#element逐行查找了

更新

@anytimecoder的回答中有一个更新的纯 JavaScript 版本——另请参阅浏览器对 getBoundingClientRect() 的支持

@Black 但有些人在 javascript 而不是 jquery 中提问,因为 jquery 在他们的环境中可能不兼容。
2021-03-11 19:19:45
它对你有用吗@ben,我很感激“正确答案”或对仍然不适合你的内容的评论。也许我可以提供更多帮助。
2021-03-18 19:19:45
这不是一个必要提:如果你复制粘贴上面的代码中,记得要纠正var y = (evt.pageY - $('#element').offset().left) + $(window).scrollTop();var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop();
2021-03-21 19:19:45
应该避免在事件处理程序中使用 $('selector') ,除非您想要非常缓慢的代码。预先选择您的元素,并在您的处理程序中使用预先选择的引用。对 $(window) 执行一次并缓存它。
2021-04-04 19:19:45
这怎么可能是答案,因为这个问题与 jQuery 无关?
2021-04-06 19:19:45

下面计算鼠标与canvas元素的位置关系:

var example = document.getElementById('example'); 
example.onmousemove = function(e) { 
    var x = e.pageX - this.offsetLeft; 
    var y = e.pageY - this.offsetTop; 
}

在这个例子中,this指的是example元素,eonmousemove事件。

也许是我,但使用关键字“this”的两行代码缺乏上下文?
2021-03-13 19:19:45
您可以切换thise.currentTarget,这将为您提供相对于您添加事件侦听器的元素的位置。
2021-03-13 19:19:45
如果某些后代元素使用相对或绝对定位,这将不起作用。
2021-03-26 19:19:45
这似乎使位置相对于元素可见部分,而不是整个元素。如果在视口中看不到部分元素并且有滚动条等,有没有办法适应这种情况?
2021-04-07 19:19:45
绝对缺乏语境。“e”是事件,“this”是事件关联的元素 var example = document.getElementById('example'); example.onmousemove = function(e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; }
2021-04-08 19:19:45

当参考元素嵌套在其他可以具有绝对定位的元素中时,纯 javascript 中没有返回相对坐标的答案。这是这种情况的解决方案:

function getRelativeCoordinates (event, referenceElement) {

  const position = {
    x: event.pageX,
    y: event.pageY
  };

  const offset = {
    left: referenceElement.offsetLeft,
    top: referenceElement.offsetTop
  };

  let reference = referenceElement.offsetParent;

  while(reference){
    offset.left += reference.offsetLeft;
    offset.top += reference.offsetTop;
    reference = reference.offsetParent;
  }

  return { 
    x: position.x - offset.left,
    y: position.y - offset.top,
  }; 

}
非常适合滚动容器,只需稍作改动:替换while(reference !== undefined)while(reference). 至少在 Chrome 中, offsetParent 最终不是undefined,而是null只需检查是否reference为真就可以确保它同时适用于undefinednull
2021-03-11 19:19:45
一般来说,检查 undefined 通常是一个坏主意
2021-03-11 19:19:45
我认为它没有考虑html元素偏移
2021-03-18 19:19:45
我认为您需要减去scrollLeftscrollTop补偿滚动的后代。
2021-04-06 19:19:45
如果可以的话,我会再给 +1,因为让我知道有一个offsetParent属性,结果证明它在其他情况下也非常有用!
2021-04-09 19:19:45

我尝试了所有这些解决方案,但由于我使用矩阵转换容器(panzoom 库)的特殊设置,没有任何效果。即使缩放和平移,这也会返回正确的值:

mouseevent(e) {
 const x = e.offsetX,
       y = e.offsetY
}

但前提是没有子元素挡路。这可以通过使用 CSS 使它们对事件“不可见”来规避:

.child {
   pointer-events: none;
}
@MarkE 没有任何可疑之处。这是 StackOverflow 的众多错误之一。您在顶部看到的那些答案是在此答案之前发布多年的,因此它们获得了巨大的投票动力。一旦某个答案获得了这种势头,就很难击败它,而且非常罕见。
2021-03-13 19:19:45
@MarkE 答案很简单:它是实验性的有些人可能在乎,有些人可能不在乎,但这是事实。
2021-03-24 19:19:45
这绝对是 2019 年的做法。其他答案都装满了旧的笨拙的包袱。
2021-03-26 19:19:45
@ColinD 谢谢!我忘了补充一点,这也适用于 IE11。
2021-03-28 19:19:45
这对我有用。但是,我怀疑 1) 很少有人赞成 2) 评分较高的答案更复杂 3) 我看不到任何缺点。有谁知道使用这种方法的任何弊端?
2021-04-03 19:19:45