坐标系统对比

区分客户区坐标、页面坐标和屏幕坐标

问题

区分什么是”客户区坐标”、“页面坐标”、“屏幕坐标”。

解答

三种坐标系统

┌─────────────────────────────────────────────────────────┐
│ 屏幕 (Screen)                                           │
│   screenX/screenY 的原点                                │
│  ┌───────────────────────────────────────────────────┐  │
│  │ 浏览器窗口                                         │  │
│  │  ┌─────────────────────────────────────────────┐  │  │
│  │  │ 视口/客户区 (Client/Viewport)               │  │  │
│  │  │   clientX/clientY 的原点                    │  │  │
│  │  │ ┌─────────────────────────────────────────┐ │  │  │
│  │  │ │                                         │ │  │  │
│  │  │ │   页面内容 (Page)                       │ │  │  │
│  │  │ │     pageX/pageY 的原点                  │ │  │  │
│  │  │ │                                         │ │  │  │
│  │  │ └─────────────────────────────────────────┘ │  │  │
│  │  └─────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

1. 客户区坐标 (Client)

相对于浏览器视口(可视区域)左上角的坐标,不受页面滚动影响

element.addEventListener('click', (e) => {
  // 相对于视口左上角
  console.log(e.clientX, e.clientY);
});

2. 页面坐标 (Page)

相对于整个页面(文档)左上角的坐标,包含滚动距离

element.addEventListener('click', (e) => {
  // 相对于页面左上角,包含滚动
  console.log(e.pageX, e.pageY);
});

3. 屏幕坐标 (Screen)

相对于用户显示器屏幕左上角的坐标。

element.addEventListener('click', (e) => {
  // 相对于屏幕左上角
  console.log(e.screenX, e.screenY);
});

完整示例

<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      height: 2000px; /* 创建滚动条 */
      padding: 100px;
    }
    #box {
      width: 200px;
      height: 200px;
      background: #3498db;
      cursor: pointer;
    }
    #info {
      position: fixed;
      top: 10px;
      right: 10px;
      background: #333;
      color: #fff;
      padding: 15px;
      font-family: monospace;
    }
  </style>
</head>
<body>
  <div id="box">点击我</div>
  <div id="info"></div>

  <script>
    const box = document.getElementById('box');
    const info = document.getElementById('info');

    box.addEventListener('click', (e) => {
      info.innerHTML = `
        <strong>客户区坐标 (Client)</strong><br>
        clientX: ${e.clientX}, clientY: ${e.clientY}<br><br>
        
        <strong>页面坐标 (Page)</strong><br>
        pageX: ${e.pageX}, pageY: ${e.pageY}<br><br>
        
        <strong>屏幕坐标 (Screen)</strong><br>
        screenX: ${e.screenX}, screenY: ${e.screenY}<br><br>
        
        <strong>页面滚动距离</strong><br>
        scrollX: ${window.scrollX}, scrollY: ${window.scrollY}
      `;
    });
  </script>
</body>
</html>

坐标转换

// page = client + scroll
const pageX = e.clientX + window.scrollX;
const pageY = e.clientY + window.scrollY;

// client = page - scroll
const clientX = e.pageX - window.scrollX;
const clientY = e.pageY - window.scrollY;

关键点

  • clientX/Y:相对于视口,不随滚动变化,常用于固定定位元素
  • pageX/Y:相对于文档,包含滚动距离,常用于获取元素在页面中的绝对位置
  • screenX/Y:相对于屏幕,用于多显示器场景或窗口定位
  • 转换公式pageX = clientX + scrollX
  • IE8 及以下不支持 pageX/Y,需要手动计算