jQuery获取鼠标在元素内的位置

174

我希望创建一个控件,用户可以在其中点击div,然后拖动鼠标,最后松开鼠标以指示他们想要的长度。 (这是为了日历控件,因此用户将指定某个事件的时间长度)

看起来最好的方法是在父div上注册“mousedown”事件,然后在div上注册“mousemove”事件,直到触发“mouseup”事件。 “mousedown”和“mouseup”事件将定义时间范围的开始和结束,随着我跟随“mousemove”事件,我可以动态更改范围的大小,以便用户可以看到自己的操作。 我基于如何在google日历中创建事件进行了操作。

我的问题在于,jQuery事件似乎只提供相对于整个页面的可靠鼠标坐标信息。 有没有办法确定相对于父元素的坐标?

编辑:

这是我想做的事情的图片: alt text

8个回答

322

一种方法是使用jQuery的offset方法将事件(event.pageXevent.pageY)转换为相对于其父元素的鼠标位置。以下是一个供以后参考的示例:

$("#something").click(function(e){
   var parentOffset = $(this).parent().offset(); 
   //or $(this).offset(); if you really just want the current element's offset
   var relX = e.pageX - parentOffset.left;
   var relY = e.pageY - parentOffset.top;
});

2
如果父元素的布局不能/不应该被更改,那么这是一个好主意! - Pointy
3
这个回答是否考虑了填充/边框? - Lee Goddard
10
根据文档,offset 不考虑 "在 body 元素上设置的边框、外边距或内边距"。我在实际使用中没有遇到问题,但最好检查是否设置了这些内容。 - jball
2
这不一定能正常工作。offset()也是相对的,所以如果父元素是其他元素的子元素,则会得到错误的结果。请改用position() - Flash Thunder
1
@FlashThunder,根据文档,offset()不是相对的,至少不是相对的。此外,在body元素上没有任何边距或填充应该是标准做法。 - James Watkins
显示剩余6条评论

18
获取点击位置相对于当前已点击元素的位置
使用此代码
$("#specialElement").click(function(e){
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
}); 

2
你的回答对我很有帮助,顺便说一下,被采纳的答案并没有。谢谢 :) 实际上我使用的是这个:var y = e.pageY - $(this).offset().top; 但是你的回答让我找到了正确的方向。 - Solomon Closson

12

我使用这段代码,它非常不错 :)

    <script language="javascript" src="http://code.jquery.com/jquery-1.4.1.js" type="text/javascript"></script>
<script language="javascript">
$(document).ready(function(){
    $(".div_container").mousemove(function(e){
        var parentOffset = $(this).parent().offset();
        var relativeXPosition = (e.pageX - parentOffset.left); //offset -> method allows you to retrieve the current position of an element 'relative' to the document
        var relativeYPosition = (e.pageY - parentOffset.top);
        $("#header2").html("<p><strong>X-Position: </strong>"+relativeXPosition+" | <strong>Y-Position: </strong>"+relativeYPosition+"</p>")
    }).mouseout(function(){
        $("#header2").html("<p><strong>X-Position: </strong>"+relativeXPosition+" | <strong>Y-Position: </strong>"+relativeYPosition+"</p>")
    });
});
</script>

10

@AbdulRahim的答案几乎正确。但是,我建议以下函数作为替代(供参考):

function getXY(evt, element) {
                var rect = element.getBoundingClientRect();
                var scrollTop = document.documentElement.scrollTop?
                                document.documentElement.scrollTop:document.body.scrollTop;
                var scrollLeft = document.documentElement.scrollLeft?                   
                                document.documentElement.scrollLeft:document.body.scrollLeft;
                var elementLeft = rect.left+scrollLeft;  
                var elementTop = rect.top+scrollTop;

                x = evt.pageX-elementLeft;
                y = evt.pageY-elementTop;

                return {x:x, y:y};
            }




            $('#main-canvas').mousemove(function(e){
                var m=getXY(e, this);
                console.log(m.x, m.y);
            });

1
非常出色的改进,救了我的一天。 - Bud Damyanov
几乎,给画布加上边距,你的边距不正确。 - Benn
这是一段很棒的代码,非常感谢! - Stefan

8

这个解决方案支持所有主流浏览器,包括IE。它还负责滚动。首先,它高效地检索元素相对于页面的位置,而不使用递归函数。然后,它获取鼠标单击相对于页面的x和y,并进行减法运算,得到相对于元素的位置(元素可以是图像或div,例如):

function getXY(evt) {
    var element = document.getElementById('elementId');  //replace elementId with your element's Id.
    var rect = element.getBoundingClientRect();
    var scrollTop = document.documentElement.scrollTop?
                    document.documentElement.scrollTop:document.body.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft?                   
                    document.documentElement.scrollLeft:document.body.scrollLeft;
    var elementLeft = rect.left+scrollLeft;  
    var elementTop = rect.top+scrollTop;

        if (document.all){ //detects using IE   
            x = event.clientX+scrollLeft-elementLeft; //event not evt because of IE
            y = event.clientY+scrollTop-elementTop;
        }
        else{
            x = evt.pageX-elementLeft;
            y = evt.pageY-elementTop;
    }

4

这里有一个可以给出点的百分比位置的方法,如果需要的话。 https://jsfiddle.net/Themezly/2etbhw01/

function ThzhotspotPosition(evt, el, hotspotsize, percent) {
  var left = el.offset().left;
  var top = el.offset().top;
  var hotspot = hotspotsize ? hotspotsize : 0;
  if (percent) {
    x = (evt.pageX - left - (hotspot / 2)) / el.outerWidth() * 100 + '%';
    y = (evt.pageY - top - (hotspot / 2)) / el.outerHeight() * 100 + '%';
  } else {
    x = (evt.pageX - left - (hotspot / 2));
    y = (evt.pageY - top - (hotspot / 2));
  }

  return {
    x: x,
    y: y
  };
}



$(function() {

  $('.box').click(function(e) {

    var hp = ThzhotspotPosition(e, $(this), 20, true); // true = percent | false or no attr = px

    var hotspot = $('<div class="hotspot">').css({
      left: hp.x,
      top: hp.y,
    });
    $(this).append(hotspot);
    $("span").text("X: " + hp.x + ", Y: " + hp.y);
  });


});
.box {
  width: 400px;
  height: 400px;
  background: #efefef;
  margin: 20px;
  padding: 20px;
  position: relative;
  top: 20px;
  left: 20px;
}

.hotspot {
  position: absolute;
  left: 0;
  top: 0;
  height: 20px;
  width: 20px;
  background: green;
  border-radius: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
  <p>Hotspot position is at: <span></span></p>
</div>


3
如果您将父元素设置为“position: relative”,那么它将成为您跟踪鼠标事件的内容的“偏移父级”。因此,jQuery中的“position()”将相对于该父级进行计算。

@DutrowLLC,Pointy建议更改父元素的样式为"position:relative"。然后,jQuery位置将相对于父元素而不是页面报告其位置。我的答案措辞不好,它暗示它与Pointy的解决方案直接相关,但这是一种在您不能或不想依赖父元素的样式属性来计算偏移量时计算偏移量的方法。 - jball
问题是关于如何获取鼠标相对于元素的位置,而不是获取元素相对于其父元素的位置,因此jQuery的position()函数在这里并没有用处。 - James Watkins
@JamesWatkins 有没有办法确定坐标是相对于父元素的? 我的回答的重点是,使用被问及元素(或适当的父元素)的相对定位可以让我们在相同的条件下解释鼠标位置和元素位置。 - Pointy
那么你应该使用offset()而不是position()。而且父元素上的"position: relative"完全无关紧要,除非在非常特定的情况下。我看不出这个答案有任何帮助的理由。 - James Watkins
这涉及到数学问题。我有一个全局于页面的光标位置 (cpx, cpy),我想找出它在位于 (px, py) 的父元素内相对于其父元素的位置。所以我做了 (cpx-px, cpy-py) 但这是错误的,因为父级的父级可能有一个位置。这里唯一的解决方案是使用 offset()。 - James Watkins
显示剩余5条评论

-1
我建议这样做:
e.pageX - this.getBoundingClientRect().left

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接