JavaScript鼠标事件中event的各种x/y属性梳理

最近在敲代码的时候遇到关于JavaScript事件中求各种长宽,涉及到event中各种x/y,所以尝试做一些梳理。

这里说的event是指js中鼠标事件event的实例属性,而各种x/y就是指以下这些:

1
2
3
4
5
6
e.clientX/e.clientY
e.screenX/e.screenY
e.offsetX/offsetY
e.pageX/e.pageY
e.layerX/e.layerX
e.x/e.y

关于各种x/y属性的描述

在网上找了一些资料,对于这些属性都有描述。http://www.w3school.com.cn w3c给出了clientX/Y跟screenX/Y的描述,不过为了统一,我选择了阮一峰的一份JavaScript教程(https://wangdoc.com/javascript/events/mouse.html) 中的描述:

1
2
3
4
5
6
7
8
9
10
11
MouseEvent.clientX属性返回鼠标位置相对于浏览器窗口左上角的水平坐标(单位像素)
MouseEvent.clientY属性返回垂直坐标。这两个属性都是只读属性。

MouseEvent.screenX属性返回鼠标位置相对于屏幕左上角的水平坐标(单位像素),
MouseEvent.screenY属性返回垂直坐标。这两个属性都是只读属性。

MouseEvent.offsetX属性返回鼠标位置与目标节点左侧的padding边缘的水平距离(单位像素)
MouseEvent.offsetY属性返回与目标节点上方的padding边缘的垂直距离。这两个属性都是只读属性。

MouseEvent.pageX属性返回鼠标位置与文档左侧边缘的距离(单位像素),
MouseEvent.pageY属性返回与文档上侧边缘的距离(单位像素)。它们的返回值都包括文档不可见的部分。这两个属性都是只读。

layerX/e.layerXx/y则没有找到比较权威的描述。

这些描述看完还是有点稀里糊涂的,不过可以看出,这些属性的值都是相对的,是有参考坐标的,比如浏览器,屏幕,目标节点,文档等。所以我们就试试在代码中获得更深入的理解。

代码实现实例属性

这里尝试做一个简单的演示项目,body中如下结构:

1
2
3
4
<div class="canvas-wrapper">
<div id="container"></div>
<canvas id="canvas" height="2000" width="2000"></canvas>
</div>

div#container元素是作为鼠标事件的目标节点,而canvas画布则是用于绘出点击事件的坐标跟垂直线。

1
2
3
4
5
* {
margin: 0px;
padding: 0px;
box-sizing: border-box;
}

由于这几个实例属性中有一些是涉及页面可视,所以给div#container元素绝对定位,脱离文档流;为了页面可以上下左右滚动,所以bodycanvas元素的尺寸都很大。
而且为了减少盒模型的影响,所以设置了box-sizing: border-box;

js逻辑部分,给div#container添加鼠标点击事件,回调函数中返回event,把event中的这些关于x/y的实例属性通过new传入一个位置构造函数的实例中,通过实例来绘出点击点跟各个x/y属性的线。

x/y各属性的表现梳理

代码中各x/y属性的演示

这张截图是在浏览器向左向下滚动后(浏览器的上边贴着绿色线,浏览器的左边贴着绿色线),点击(点击点中心为黑点中心)触发事件得到的绘图。

clientX/clientY & x/y

clientX/clientY在点击事件触发时是等于点击点到浏览器的上边跟左边,说明 clientX/clientY的参考坐标轴是沿着浏览器的上边为x轴,浏览器的左边为y轴 。跟目标节点的bordermarginpadding没有关系。
相同的x/y在表现上也一样。不过最好使用的时候使用前者。

layerX/layerY

layerX/layerY在点击事件触发之后显示出来是点击点到目标节点的边界,而且是在目标节点的边框上。目标节点的样式是有添加borderpadding样式的,而这个属性绘出的线跟目标节点的边框相交但不超出,说明 layerX/layerY的参考坐标轴是沿着目标节点的上边界(有边框则是沿着上边框)为x轴,目标节点的左边界(有边框则是沿着左边框)为y轴 。跟目标节点的margin,页面的可视范围没有关系。

offsetX/offsetY

offsetX/offsetYlayerX/layerY很接近,但是它跟目标节点的边框没有相交,也就是当目标节点没有边框的情况下,offsetX/offsetYlayerX/layerY的值是相等的。offsetX/offsetY的参考坐标轴是沿着目标节点的上边界为x轴,目标节点的左边界为y轴 。跟目标节点的margin,页面的可视范围没有关系。

pageX/pageY

pageX/pageY在点击事件触发之后显示出来是点击点到文档页面的边界,及时是页面发生了滚动,这个属性仍然显示的是点击点在文档页面的相对位置。所以 pageX/pageY的参考坐标轴是沿着文档页面的上边界为x轴,文档页面的左边界为y轴 。跟目标节点,页面的可视范围没有关系。

screenX/screenY

screenX/screenY代码中没有绘制,原因在于这个属性的坐标是整个屏幕,跟浏览器无关,所以无法绘制展示出来。

上述就是鼠标事件event中关于x/y属性的梳理。文中的代码已上传github:
https://github.com/listentolife/mouseEventPositionAttributes