28

我目前有一个 div,其中包含其他元素。

类似于下面的东西;

<div id="container" style="position: relative; width: 500px; height: 500px;">
     <div style="position: absolute; left: 50px; top: 50px;"></div>
     <div style="position: absolute; left: 100px; top: 100px;"></div>
</div>

我正在尝试使用 id 获取鼠标相对于 div 的位置container

到目前为止,我有这个;

function onMousemove(event) {

    x = event.offsetX;
    y = event.offsetY;
};

var elem = document.getElementById("container");
elem.addEventListener("mousemove", onMousemove, false);

如果具有 id 的 divcontainer没有子级,这可以正常工作。当containerdiv 有子元素时,它会获取相对于子元素而不是父元素的鼠标坐标。

我的意思是,如果鼠标位于x: 51, y: 51相对于父 div 的位置,它实际上会x: 1, y: 1使用上面给出的 html 相对于子 div 返回。

我怎样才能实现我想要的,请不要图书馆。

编辑

tymeJV 对上面发生的事情做了一个 jsfiddle。

http://jsfiddle.net/N6PJu/1

4

6 回答 6

81

接受的答案在 Chrome 中对我不起作用。这是我解决它的方法:

function relativeCoords ( event ) {
  var bounds = event.target.getBoundingClientRect();
  var x = event.clientX - bounds.left;
  var y = event.clientY - bounds.top;
  return {x: x, y: y};
}
于 2015-10-26T14:01:34.727 回答
9

本质上:'mouseposition' - '父元素位置' = 'mouseposition 相对于父元素'

所以在这里我修改了你的功能:

function onMousemove(e){
    var m_posx = 0, m_posy = 0, e_posx = 0, e_posy = 0,
           obj = this;
    //get mouse position on document crossbrowser
    if (!e){e = window.event;}
    if (e.pageX || e.pageY){
        m_posx = e.pageX;
        m_posy = e.pageY;
    } else if (e.clientX || e.clientY){
        m_posx = e.clientX + document.body.scrollLeft
                 + document.documentElement.scrollLeft;
        m_posy = e.clientY + document.body.scrollTop
                 + document.documentElement.scrollTop;
    }
    //get parent element position in document
    if (obj.offsetParent){
        do { 
            e_posx += obj.offsetLeft;
            e_posy += obj.offsetTop;
        } while (obj = obj.offsetParent);
    }
    // mouse position minus elm position is mouseposition relative to element:
    dbg.innerHTML = ' X Position: ' + (m_posx-e_posx) 
                  + ' Y Position: ' + (m_posy-e_posy);
}

var elem = document.getElementById('container');
elem.addEventListener('mousemove', onMousemove, false);

var dbg=document.getElementById('dbg');  //debut output div instead of console

这是一个工作演示小提琴。正如您在代码中所读到的,这也会查看文档的滚动位置。

PPK 关于“事件属性”和“查找位置”的文章(一如既往)是一本好书!

希望这可以帮助!

更新:
我实际上在 ppk 的代码中发现了一个错误(这有多罕见?!):我纠正了错误var
if (!e) var e = window.event;if (!e){e = window.event;}

于 2013-04-22T20:24:01.023 回答
2

html

<div id="container" style="position: relative; width: 500px; height: 500px;">
<div style="position: absolute; left: 50px; top: 50px;"></div>
<div style="position: absolute; left: 100px; top: 100px;"></div>
</div>

Javascript

function onMousemove(event) {
    x = event.layerX; // position x relative to div
    y = event.layerY; // position y relative to div 
};

var elem = document.getElementById("container");
elem.addEventListener("mousemove", onMousemove, false);
于 2014-09-22T12:48:34.383 回答
1

获取 screenX 和 screenY 属性以查看鼠标在屏幕上的位置(并可能考虑到 scrollHeight!)。

然后获取容器元素的left和top,计算它们之间的偏移量:即鼠标在元素中的位置。

有关更多详细信息,请参阅https://developer.mozilla.org/en-US/docs/DOM/MouseEvent

于 2013-04-22T20:01:10.623 回答
1

使用函数式组件,您可以结合useRef事件click监听器(而不需要直接引用 DOM):

const MyElement = () => {
  const ref = useRef(null);

  useEffect(() => {
    const currentRef = ref.current;
    if (currentRef) {
      const clickListener = (e) => {
        const rightOfElement = currentRef.getBoundingClientRect().right;
        const leftOfElement = currentRef.getBoundingClientRect().left;
        const mousePosXRelativeToElement = e?.clientX ?? 0;

        const mousePosX = rightOfElement - mousePosXRelativeToElement;
        const fullWidth = rightOfElement - leftOfElement;

        // do something, e.g. changing state based on position
        if (mousePosX / fullWidth < 0.5) {
          setTheme(2);
        } else {
          setTheme(1);
        }
      };
      currentRef.addEventListener("click", clickListener);
      return () => {
        currentRef.removeEventListener("click", clickListener);
      };
    }
  }, [setTheme]);

  return (
    <div className="theme-selector-wrapper">
      <div className="theme-selector" ref={ref}></div>
    </div>
  );
};

在内部useEffect(即一旦加载元素),将事件侦听器添加到分配给ref侦听点击的元素的元素。在此示例中,我根据 X 位置与元素宽度的比率更改了“主题”。

于 2021-05-18T22:18:37.660 回答
0

尽管 Nikita Volkov 的回答非常可靠,但在某些情况下它可能无法按预期工作。

我建议使用currentTarget而不是target

const handleEvent = (event) => 
{
  const bounds = event.currentTarget.getBoundingClientRect();
  const x = event.clientX - bounds.left;
  const y = event.clientY - bounds.top;
  // Now x and y are the relative coordinates.
}

注意:

  • event.target是触发事件的元素(例如,用户点击或悬停在上面)。
  • event.currentTarget是事件侦听器附加到的元素。

当您想将侦听器附加到具有多个子元素的某个元素时,它会有所不同。

例如,

<div onMouseMove={handleEvent} id="div0">
  <div style={{'height': 200, 'width': 200}} id="div1">
  </div>
  <div style={{'height': 200, 'width': 200}} id="div2">
  </div>
</div>

如果您使用event.target并将鼠标悬停在上方div2,您将获得相关的相对坐标,div2而您可能希望它们相关div0。然后event.currentTarget会做的伎俩。

于 2022-02-04T10:54:30.580 回答