核心概念:两种坐标系统

要理解鼠标位置,首先要明白网页中的两种坐标系统:

js获取鼠标在网页上的位置
(图片来源网络,侵删)
  1. 视口坐标

    • 定义:相对于浏览器窗口(或者说,浏览器可视区域)左上角的坐标。
    • 特点:当用户滚动页面时,同一个元素在视口中的位置会改变,但它的视口坐标也随之改变,这个坐标不受页面滚动的影响。
    • 对应属性event.clientXevent.clientY
  2. 文档坐标

    • 定义:相对于整个 HTML 文档(从 <body><html> 的左上角开始)的坐标。
    • 特点:这是元素的“绝对”位置,即使你滚动页面,一个元素在文档中的坐标也是固定的,这个坐标包含了页面滚动带来的偏移量。
    • 对应属性event.pageXevent.pageY

简单比喻

  • 视口坐标 就像你在房间里,相对于房间墙壁的位置,你往前走,房间里的家具相对于你的位置就变了。
  • 文档坐标 就像家具在整个城市地图上的绝对地址,无论你在房间的哪个角落,家具的地址是不变的。

如何获取鼠标位置

你需要监听鼠标移动事件,通常是 mousemove 事件。

js获取鼠标在网页上的位置
(图片来源网络,侵删)

获取鼠标在视口中的位置 (clientX, clientY)

这是最简单直接的方法,适用于大多数不需要考虑页面滚动的场景,比如拖拽元素、创建跟随鼠标的菜单等。

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">获取鼠标位置 (clientX, clientY)</title>
    <style>
        body {
            height: 200vh; /* 为了演示滚动效果,让页面变长 */
            font-family: sans-serif;
        }
        #info {
            position: fixed;
            top: 10px;
            left: 10px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 10px;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <div id="info">
        <p>鼠标在视口中的位置:</p>
        <p>X: <span id="clientX">0</span></p>
        <p>Y: <span id="clientY">0</span></p>
    </div>
    <script>
        // 获取显示位置的元素
        const clientXSpan = document.getElementById('clientX');
        const clientYSpan = document.getElementById('clientY');
        // 为整个文档添加 mousemove 事件监听器
        document.addEventListener('mousemove', (event) => {
            // event.clientX 和 event.clientY 提供了相对于视口的坐标
            clientXSpan.textContent = event.clientX;
            clientYSpan.textContent = event.clientY;
        });
    </script>
</body>
</html>

说明

  • document.addEventListener('mousemove', ...) 会在鼠标在页面的任何位置移动时触发回调函数。
  • event 对象是事件对象,包含了关于事件的详细信息,其中就包括鼠标坐标。
  • event.clientX 是鼠标在视口中的 X 坐标。
  • event.clientY 是鼠标在视口中的 Y 坐标。

获取鼠标在文档中的位置 (pageX, pageY)

当你需要获取鼠标在页面“绝对”位置时,应该使用 pageXpageY,这在实现全页面交互、绘制 Canvas、或者需要精确计算元素相对于文档位置的场景中非常有用。

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">获取鼠标位置 (pageX, pageY)</title>
    <style>
        body {
            height: 200vh; /* 为了演示滚动效果 */
            font-family: sans-serif;
        }
        #info {
            position: fixed;
            top: 10px;
            right: 10px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 10px;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <div id="info">
        <p>鼠标在文档中的位置:</p>
        <p>X: <span id="pageX">0</span></p>
        <p>Y: <span id="pageY">0</span></p>
    </div>
    <script>
        // 获取显示位置的元素
        const pageXSpan = document.getElementById('pageX');
        const pageYSpan = document.getElementById('pageY');
        // 为整个文档添加 mousemove 事件监听器
        document.addEventListener('mousemove', (event) => {
            // event.pageX 和 event.pageY 提供了相对于文档的坐标
            pageXSpan.textContent = event.pageX;
            pageYSpan.textContent = event.pageY;
        });
    </script>
</body>
</html>

说明

  • event.pageX 是鼠标在文档中的 X 坐标。
  • event.pageY 是鼠标在文档中的 Y 坐标。
  • 注意:当你滚动页面时,即使鼠标在视口中的位置不变,pageXpageY 的值也会随着滚动而增加。

重要注意事项

pageXpageY 的兼容性

pageXpageY 在所有现代浏览器(Chrome, Firefox, Safari, Edge)中都得到了很好的支持,但在一些非常旧的浏览器(如 IE8 及更早版本)中可能不被支持。

如果你的项目需要兼容这些旧浏览器,可以手动计算 pageXpageY

// 兼容旧浏览器的写法
let x = event.clientX + window.scrollX;
let y = event.clientY + window.scrollY;
// 或者使用 event.pageX 和 event.pageY,如果不存在则用上面的计算方式
let x = event.pageX || (event.clientX + window.scrollX);
let y = event.pageY || (event.clientY + window.scrollY);
  • window.scrollXwindow.scrollY 获取页面水平和垂直方向的滚动距离。

监听事件的目标

上面的例子中,我们在 document 上监听了 mousemove 事件,这意味着只要鼠标在浏览器窗口内移动,事件就会被触发。

如果你只想在某个特定的元素上跟踪鼠标,你应该在该元素上添加事件监听器:

<div id="myBox" style="width: 300px; height: 200px; background: lightblue; margin: 50px;">
    将鼠标移动到这里
</div>
<script>
    const myBox = document.getElementById('myBox');
    myBox.addEventListener('mousemove', (event) => {
        // 这里的坐标是相对于 myBox 这个元素的左上角
        console.log(`相对于 myBox 的 X: ${event.offsetX}, Y: ${event.offsetY}`);
        console.log(`相对于视口的 X: ${event.clientX}, Y: ${event.clientY}`);
    });
</script>

这里出现了另一个有用的属性:

  • offsetX / offsetY:返回鼠标事件发生的位置相对于目标元素的坐标,这在处理特定元素的交互时非常有用。

总结与对比

属性 坐标系统 描述 是否受页面滚动影响 兼容性
clientX 视口 相对于浏览器窗口左上角。 优秀
clientY 视口 相对于浏览器窗口左上角。 优秀
pageX 文档 相对于整个文档的左上角。 良好 (IE9+)
pageY 文档 相对于整个文档的左上角。 良好 (IE9+)
offsetX 目标元素 相对于事件目标元素的内边距边缘。 良好 (IE9+)
offsetY 目标元素 相对于事件目标元素的内边距边缘。 良好 (IE9+)

如何选择?

  • 创建跟随鼠标的 UI(如工具提示、自定义光标):使用 clientXclientY,因为它们不受滚动影响,定位更稳定。
  • 在 Canvas 或 SVG 上绘图:使用 pageXpageY,因为画布是文档的一部分,你需要知道它在文档中的绝对位置。
  • 处理特定元素的拖拽或点击区域:使用 offsetXoffsetY,可以轻松知道点击发生在元素内部的哪个位置。

希望这个详细的解释能帮助你完全理解在 JavaScript 中获取鼠标位置的各种方法!