在开发中处理鼠标事件时,经常会碰到 offset、scroll、client 这几个关键字,每次处理页面元素的坐标和偏移前,都要网上去搜资料,还会踩一些坑,影响开发效率。这里总结一下,一劳永逸。
一、图解HTML的四个坐标系统
HTML有四个常见的坐标系统:screen,page,client和offset,用于描述DOM元素的Box尺寸和MouseEvent中的位置。
如下图所示:
1. screen坐标系
参照点:用户显示器屏幕左上角。
screenX:鼠标点击位置相对于电脑屏幕左上角的水平偏移量。
screenY:鼠标点击位置相对于电脑屏幕左上角的垂直偏移量。
screen坐标的最大范围是 (screen.width, screen.height),最大值不会超过屏幕分辨率。
补充:
// 屏幕宽度。
screen.width
// 屏幕高度。
screen.height
// 屏幕可用宽度。即屏幕宽度减去左右任务栏后的宽度,可表示为浏览器最大化时的宽度。
screen.availWidth
// 屏幕可用高度。即屏幕高度减去上下任务栏后的高度,可表示为浏览器最大化时的高度。
screen.availHeight
// 任务栏高/宽度。如:任务栏高/宽度 = 屏幕高/宽度 - 屏幕可用高/宽度。
screen.height - screen.availHeight
2. page坐标系
参照点:整个页面的左上角(整个页面的意思就是你整个网页的全部,按照整个html文档的长度和宽度来计算)。
pageX:鼠标点击位置相对于网页左上角的水平偏移量,也就是 clientX + 水平滚动条滚动的距离。
pageY:鼠标点击位置相对于网页左上角的垂直平偏移量,也就是 clientY + 垂直滚动条滚动的距离。
* 因此,坐标系上某一个元素的pageX/pageY 不会 随着滚动条滚动而改变。
page坐标的最大范围是 (document.body.clientWidth + 垂直滚动条宽度, document.body.clientHeight + 水平滚动条高度)。
* 比如说网页很宽很长,宽2000px,高3000px,那 pageX/pageY 的最大值就是它们了。
补充:
// 浏览器宽度。
window.outerWidth
// 浏览器高度。
window.outerHeight
// 浏览器内页面可用宽度,此宽度包含了垂直滚动条的宽度(若存在)。可表示为浏览器当前宽度去除浏览器边框后的宽度。
window.innerWidth
// 浏览器内页面可用高度,此高度包含了水平滚动条的高度(若存在)。可表示为浏览器当前高度去除浏览器边框、工具条后的高度。
window.innerHeight
// 工具栏高/宽度,包含了地址栏、书签栏、浏览器边框等范围。如:工具栏高度 = 浏览器高度 - 页面可用高度。
window.outerHeight - window.innerHeight
3. client
参照点:浏览器内容区域左上角(即浏览器中用户所看到区域的左上角,内容区域不包括工具栏和滚动条)。
clientX:鼠标点击位置相对于浏览器可视区域的水平偏移量(不会计算水平滚动的距离)。
clientY:鼠标点击位置相对于浏览器可视区域的垂直偏移量(不会计算垂直滚动的距离)。
* 因此,坐标系上某一个元素的clientX/clientY 会 随着滚动条滚动而改变。
client坐标的最大范围是 (window.innerWidth - 垂直滚动条宽度, window.innerHeight - 水平滚动条高度)。
* 计算这个坐标时,由于是基于浏览器窗口中用来显示网页的可视区域,那么也就是说需要拖动滚动条才能看到的区域不算;当你将浏览器窗口缩小时,clientX/clientY 的最大值也会缩小,但始终,它们的最大值不会超过你浏览器可视区域。
补充:
// body展示的宽度,表示body在浏览器内显示的区域宽度。
document.body.clientWidth
// body展示的高度,表示body在浏览器内显示的区域高度。
document.body.clientHeight
4. offset
参照点:父级中最近的一个带有CSS定位(position为absolute/relative)的父元素,如果当前元素的父级元素中没有进行CSS定位,那么就是body。
offsetX:鼠标点击位置相对于触发事件对象的水平距离。
offsetY:鼠标点击位置相对于触发事件对象的垂直距离。
offset坐标的最大范围是 (document.body.offsetWidth, document.body.offsetHeight)。
补充:
// body总宽度。
document.body.offsetWidth
// body总高度。
document.body.offsetHeight
二、图解鼠标事件坐标
鼠标事件都是在特定位置发生的,我们可以通过event事件对象的各种属性来获得事件发生的坐标位置。
常见的鼠标事件有下面这几种:
1. onclick
鼠标点击事件
let el = document.querySelector('#element-id');
el.onclick = function(e){
console.log(e)
}
2. onmousedown
鼠标按下事件
let el = document.querySelector('#element-id');
el.onmousedown = function(e){
console.log(e)
}
3. onmouseup
鼠标松开事件
let el = document.querySelector('#element-id');
el.onmouseup = function(e){
console.log(e)
}
4. onmousemove
鼠标移动事件
let el = document.querySelector('#element-id');
el.onmousemove = function(e){
console.log(e)
}
5. onmouseover
鼠标经过事件
let el = document.querySelector('#element-id');
el.onmouseover = function(e){
console.log(e)
}
6. onmouseout
鼠标划出事件
let el = document.querySelector('#element-id');
el.onmouseout = function(e){
console.log(e)
}
根据以上打印的e的信息,大致为:
由鼠标事件(MouseEvent)可以发现:其中包含了许多的坐标,且每个坐标的含义都不一样。下面我们来挨个介绍常用的坐标,以及它们的含义。
如图所示,假设页面中灰色圆点是鼠标点击处,棕色区域是鼠标触发事件对象。

结合前面的图,我们可以看到:e.x,e.y分别和e.clientX,e.clientY相等。
事实上,e.layerX/e.layerY 与 e.x/e.y 这两个属性比较特殊。考虑到它们不那么常见(因为受浏览器种类影响),而且使用时需要考虑的情况相对复杂(layerX/layerY对于absolute绝对定位元素,参考点是当前点击元素的左上角;对于relative相对定位元素,通常与pageX/pageY的值是相同的),这里不展开讨论(实用主义,感兴趣的可以单独拎出来尝试)。
三、不同浏览器对这些属性的支持
Chrome | Firefox | IE8 - | IE9 | IE10 + | |
---|---|---|---|---|---|
offsetX | √ | × | √ | √ | √ |
clientX | √ | √ | √ | √ | √ |
pageX | √ | √ | × | √ | √ |
screenX | √ | √ | √ | √ | √ |
layerX | √ | √ | × | √ | √ |
x | √ | × | √ | √ | √ |
上面列举的这些浏览器都在不断迭代版本,而且市面上还有很多其它浏览器,所以这部分内容需要实时参考MDN上的浏览器兼容性表格。
四、总结
上面那些属性都是很容易搞混的,常用的记在这里方便以后速查。一些特殊的属性尤其要注意不同的浏览器中可能存在的差别,使用的时候测试一下就能更准确的应用了。
整理这篇文章的契机,就是我在编写cceditor这个项目的时候。
如有异议,可以在留言区评论,或直接发送您宝贵的意见至我的邮箱。
参考
MDN
若干文章