javascript 事件对象 坐标事件说明

所属分类: 网络编程 / JavaScript 阅读数: 1747
收藏 0 赞 0 分享
测试浏览器的版本:

IETester 6 ,7
IE 8.0
Firefox 3.5.5
Chrome 4.1.249.1064 (45376)
Opera 9.64
Safari 4.0


先来看看各个主流浏览器都有哪些坐标属性以及它们的意义

在IE中

event.offsetX
event.offsetY
相对于e.srcElement坐标
设置或获取鼠标指针位置相对于触发事件的对象的 x 坐标。
设置或获取鼠标指针位置相对于触发事件的对象的 y 坐标。


event.clientX
event.clientY
总是相对于视口
设置或获取鼠标指针位置相对于窗口客户区域的 x 坐标,其中客户区域不包括窗口自身的控件和滚动条。
设置或获取鼠标指针位置相对于窗口客户区域的 y 坐标,其中客户区域不包括窗口自身的控件和滚动条。


event.x
event.y
虽然手册上说是相对于文档,但是ie6/7 中,他们俩的值跟clientX,clientY一致
但是这并不是严重的问题,因为视口相对坐标加上滚动条已卷去高度,依然可以得到真实的x(y),这个问题在ie8的标准模式下被解决

设置或获取鼠标指针位置相对于父文档的 x 像素坐标。
设置或获取鼠标指针位置相对于父文档的 y 像素坐标。

event.screenX
event.screenY
设置或获取获取鼠标指针位置相对于用户屏幕的 x 坐标。
设置或获取获取鼠标指针位置相对于用户屏幕的 y 坐标。

在FireFox中

event.layerX
event.layerY
相对于e.srcElement坐标
设置或获取鼠标指针位置相对于触发事件的对象的 x 坐标。
设置或获取鼠标指针位置相对于触发事件的对象的 y 坐标。

event.clientX
event.clientY
总是相对于视口
设置或获取鼠标指针位置相对于窗口客户区域的 x 坐标,其中客户区域不包括窗口自身的控件和滚动条。
设置或获取鼠标指针位置相对于窗口客户区域的 y 坐标,其中客户区域不包括窗口自身的控件和滚动条。


event.pageX
event.pageY
设置或获取鼠标指针位置相对于父文档的 x 像素坐标。
设置或获取鼠标指针位置相对于父文档的 y 像素坐标。


event.screenX
event.screenY
设置或获取获取鼠标指针位置相对于用户屏幕的 x 坐标。
设置或获取获取鼠标指针位置相对于用户屏幕的 y 坐标。


实际上IE和Firefox已经囊括了所有的属性,其他的浏览器将这些属性进行了组合,但是意义完全一致

Chrome 和 Safari
Chrome和Safari这哥俩办事儿则灰常周全,它们收录了所有的坐标属性,包括

event.offsetX
event.offsetY
event.layerX
event.layerY

event.clientX
event.clientY

event.x
event.y
event.pageX
event.pageY

注意:Chrome和Safari的event.x event.y 跟IE6 7 的表现一致,它们和event.clientX,event.clientY相等


Opera坚定的走了ie6 7的道路,它拥有

event.offsetX
event.offsetY

event.clientX
event.clientY

event.x
event.y
差点就和ie一模一样,幸好它有pageX,pageY
event.pageX
event.pageY

注意:Chrome和Safari,以及 Opera 的event.x event.y 都跟IE6 7 的表现一致,它们和event.clientX,event.clientY相等,
而在ie8中,event.x,event.y 则等同于 其他浏览器的event.pageX,event.pageY


为啥米layerX和offsetX, x,和pageX会在某些浏览器里重复出现捏?
因为W3C并没有标准化这些属性,DOM3草案里MouseEvent部分沿用了DOM2的定义,只有两对属性

clientX of type long, readonly
The horizontal coordinate at which the event occurred relative to the viewport associated with the event.
clientY of type long, readonly
The vertical coordinate at which the event occurred relative to the viewport associated with the event

screenX of type long, readonly
The horizontal coordinate at which the event occurred relative to the origin of the screen coordinate system.
screenY of type long, readonly
The vertical coordinate at which the event occurred relative to the origin of the screen coordinate system.

这下杯具了,所以支持标准的浏览器们都木有了方向,但是吧,浏览器厂商转念一想,W3C反正也弄不出幺蛾子来,肯定从offsetXY 和 layerXY,
pageXY 和 xy中间挑一个,于是为了迎合标准,就把这两对属性就都放进了浏览器中。

不管怎么样,出了问题总是要解决掉。看到上面的兼容报告,代码雏形也就做好了

我们开始动手写!

getEventCoord
复制代码 代码如下:

1 var getEventCoord = function( e )
2 {
3 var evt = e||event;
4 var html = document.documentElement; //滚动条在<HTML>上
5 return {
6
7 //如果pageX属性为真 就使用pageX,否则就使用 clientX + html.scrollLeft
8 pageX : evt.pageX || evt.clientX + html.scrollLeft,
9
10 //如果pageY属性为真 就使用pageY,否则就使用 clientY + html.scrollTop
11 pageY : evt.pageY || evt.clientY + html.scrollTop,
12
13 //clientX Y 大家都一致,木有悬念
14 clientX : evt.clientX,
15 clientY : evt.clientY,
16
17 //如果layerX属性为真 就使用layerX,否则就使用 offsetX
18 layerX : evt.layerX || evt.offsetX,
19
20 //如果layerY属性为真 就使用layerY,否则就使用 offsetY
21 layerY : evt.layerY || evt.offsetY
22 }
23 }


用法如下
复制代码 代码如下:

document.onmousemove = function( e )
{
var coord = getEventCoord(e);
document.title = [coord.pageX,coord.pageY];
}


看起来已经灰常的OK,似乎已经能满足日常工作需要了,但还是存在几个问题

1.不严谨

使用 evt.pageX || evt.clientX + html.scrollLeft 这种判断,
只要evt.pageX 等于 undefined,null,NaN,'',0,false 这些值,左边的表达式结果就为false,从而计算右边的表达式并返回表达式的值,
而evt.pageX本身就是有机会返回0的。所以这条判断应该改为
typeof evt.pageX == 'number' ? evt.pageX : evt.clientX + html.scrollLeft
pageX是个数字的时候我们才使用它

2.无法工作在怪异模式中

什么是怪异模式?

IE为了兼容IE56之前版本,在ie6中引入了两种渲染模式: 怪异模式(Quicks Mode) 和 标准模式 (Standards Mode)
两种模式差异主要集中在css的盒模型解释方面,而BOM中。则是滚动条的依赖对象发生了变化
在怪异模式中,滚动条是body的,如果想取得页面的滚动卷去的高度和宽度,需要使用document.body.scrollTop
而标准模式中需要使用document.documentElement.scrollTop

而两种模式的切换方式主要是由doctype来确定,参见:http://dancewithnet.com/2009/06/14/activating-browser-modes-with-doctype/

从ie6开始,ie使用一个属性 document.compatMode 来检测文档是否切换到了怪异模式还是处在标准模式
如果document.compatMode的值
为BackCompat:就是在怪癖模式下
为CSS1Compat:就是在标准模式下


所以这里为了在两个模式中都工作正常,
我们需要判断document.compatMode是哪个模式
而判断的方式也很简单,只需要判断compatMode的值的第一个字母是否为b,就可以选择scrollTop的依赖对象
判断方式可以这么写
document.compatMode.indexOf('b')==0
也可以用正则写
/^b/i.test( document.compatMode )
第二种显得更牛x一点。。嗯,就用第二种(实际上第一种性能好一点)

现在再来写第二版吧

代码
复制代码 代码如下:

var getEventCoord = function( e )
{
var evt = e||event, d = document,
scrollEl = /^b/i.test( d.compatMode ) ? d.body : d.documentElement,
supportPage = typeof evt.pageX == 'number',
supportLayer = typeof evt.layerX == 'number'
return {
pageX : supportPage ? evt.pageX : evt.clientX + scrollEl.scrollLeft,
pageY : supportPage ? evt.pageY : evt.clientY + scrollEl.scrollTop,
clientX : evt.clientX,
clientY : evt.clientY,
layerX : supportLayer ? evt.layerX : evt.offsetX,
layerY : supportLayer ? evt.layerY : evt.offsetY
}
}


噔噔噔噔,这就搞定了,这个函数能干啥哩,首先想到的就是拖拽,让我们写一个小小的拖拽函数验证一下下

代码
复制代码 代码如下:

function dragMe( o )
{
var supportCapt = !!o.setCapture;
o.onmousedown = function(e)
{
var coord = getEventCoord(e), x = coord.layerX, y = coord.layerY;
if( supportCapt ) o.setCapture();
document.onmousemove = function(e)
{
var coord = getEventCoord(e);
o.style.left = coord.pageX - x + 'px';
o.style.top = coord.pageY - y + 'px';
}
document.onmouseup = function()
{
this.onmousemove = this.onmouseup = null;
if( supportCapt ) o.releaseCapture();
}
}
}
dragMe( document.getElementById('block') );

例子

[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]
更多精彩内容其他人还在看

js实现图片上传预览原理分析

这篇文章主要为大家详细介绍了js实现图片上传预览的原理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Angular限制input框输入金额(是小数的话只保留两位小数点)

最近做项目遇到这样的需求输入框要求输入金额,只能输入数字,可以是小数,必须保留小数点后两位。下面分为两部分代码给大家介绍实现代码,需要的的朋友参考下吧
收藏 0 赞 0 分享

详解vue-cli + webpack 多页面实例配置优化方法

本篇文章主要介绍了详解vue-cli + webpack 多页面实例配置优化方法,具有一定的参考价值,有兴趣的可以了解一下
收藏 0 赞 0 分享

详解React-Native解决键盘遮挡问题(Keyboard遮挡问题)

本篇文章主要介绍了React-Native解决键盘遮挡问题(Keyboard遮挡问题),具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

JavaScript反弹动画效果的实现代码

本文通过实例代码给大家介绍了js反弹动画效果的实现代码,需要的朋友参考下吧
收藏 0 赞 0 分享

解决vue2.x中数据渲染以及vuex缓存的问题

本篇文章主要介绍了vue2.x中请求之前数据显示以及vuex缓存的问题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

jsonp跨域请求详解

这篇文章主要为大家详细介绍了jsonp跨域请求的相关资料,激活了所有接口支持浏览器跨域请求的封装,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

解决vue里碰到 $refs 的问题的方法

本篇文章主要介绍了解决vue里碰到 $refs 的问题的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

js自定义弹框插件的封装

这篇文章主要为大家详细介绍了js自定义弹框插件的简单封装,自己封装一个弹框插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

深入理解vue $refs的基本用法

本篇文章主要介绍了深入理解vue $refs的基本用法 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享
查看更多