jQuery获取元素内的鼠标位置


165

我希望制作一个控件,使用户可以在div内单击,然后拖动鼠标,然后放开鼠标以指示他们想要某个东西的时间。(这是用于日历控件的,因此用户将及时指示某个事件的时长)

看起来最好的方法是在父div上注册“ mousedown”事件,然后在div上注册“ mousemove”事件,直到触发“ mouseup”事件为止。“ mousedown”和“ mouseup”事件将定义时间范围的开始和结束,并且当我跟随“ mousemove”事件时,我可以动态更改范围的大小,以便用户可以看到他们在做什么。我基于这是如何在Google日历中创建事件的。

我遇到的问题是jQuery事件似乎仅提供了引用整个页面的可靠鼠标坐标信息。有什么方法可以识别相对于父元素的坐标?

编辑:

以下是我要执行的操作的图片: 替代文字

Answers:


305

一种方法是使用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

2
这个答案是否考虑了填充/边界?
LeeGee 2013年

10
根据文档,offset不考虑“在body元素上设置的边框,边距或填充”。我发布的答案在使用中没有遇到问题,但是检查设置的内容可能会很好。
jball 2013年

2
这不必工作。offset()也是相对的,因此,如果父对象是其他元素的子对象,则会产生错误的结果。使用position()代替。
Flash Thunder

1
@FlashThunder offset()不是相对的,至少不是根据文档。同样,应该标准的做法是在body元素上没有任何空白或填充。
James Watkins 2015年

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;但是,您的回答使我走上了正确的道路。
所罗门·克洛森

11

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

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

9

@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
辉煌的进步,拯救了我的一天。
巴德·达米扬诺夫

几乎,在画布上添加页边空白,您就会被页边空白
Benn

这是一段很棒的代码,非常感谢!
斯特凡(Stefan),2018年

7

该解决方案支持所有主要浏览器,包括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;
    }

3

如果将父元素设为“ position:relative”,那么它将成为您要跟踪鼠标事件的内容的“偏移父元素”。因此,jQuery“ position()”将相对于此。


嗨Pointy,谢谢您的回复。根据您的措辞,听起来您的建议与jball的建议有所不同,但是我不理解如何,您能否详细说明?再次感谢
克里斯·杜特洛

@ DutrowLLC,Pointy建议将父元素的样式更改为have "position:relative"。然后,jQuery位置将报告其相对于父元素而不是页面的位置。我的答案的措辞很差,暗示它与Pointy的解决方案直接相关,但是当您不愿或不想依赖父元素的样式属性时,这是一种计算偏移量的方法。
jball 2010年

因此,如果我设置“ position:relative”,jQuery将在所有浏览器中正确报告相对位置?我问的原因是因为jQuery文档似乎暗示所有浏览器中唯一可靠的鼠标位置是相对于浏览器窗口本身的鼠标位置。
克里斯·杜特罗

具有“ position:relative”的框将通过相对于相对父框的内容矩形来设置子框的“ top”和“ left”(等)设置。
Pointy 2010年

我可能做错了什么,但这在Firefox中似乎不起作用。我有“ position:relative;” 设置在父级中,firefox以相同的方式(相对于页面的顶部,左侧)报告event.pageX和event.clientX,并报告undefined的event.offsetX
Chris

2

如果需要的话,这里还提供了该点的百分比位置。 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>


-1

我建议这样做:

e.pageX - this.getBoundingClientRect().left
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.