JavaScript Event学习第九章 鼠标事件


Posted in Javascript onFebruary 08, 2010

先看看都有哪些鼠标事件:mousedown,mouseup_and_click,dblclick,mousemove和mouseover mouseout。然后还会解释一下relatedTarget,fromElement和toElement这些事件属性。最后是微软的mouseenter和mouseleave事件。

浏览器的兼容性问题,可以在浏览器兼容性列表查看。

例子
这里有一个例子。可以帮助理解下面的内容。
mousedown,mouseup,click和dblclick在这个链接上注册。可以再下面的文本框里面查看。或者在对话框里面。(请在原文里尝试:http://www.quirksmode.org/js/events_mouse.htm
Mousedown,mouseup,click
如果用户在一个元素上点击,那么最少三个事件会被触发,顺序是这样的:
1、mousedown,当用户在这个元素上按下鼠标键的时候
2、mouseup,当用户在这个元素上松开鼠标键的时候
3、click,当一个mousedown和一个mouseup都在这个元素上被检测到的时候发生
通常mousedown和mouseup比click有用。有些浏览器不允许你读取onclick的事件信息。而且有时候用户用鼠标做出某些动作click事件没有跟上。
假设用户在一个链接上按下了鼠标键,然后把鼠标挪开了并且挪开后松开了鼠标键。那么这时候这个链接就仅仅发生了mousedown事件。类似的,用户在点击鼠标之后挪到了链接上,那么链接就仅有mouseup发生。这两种情况都没有click事件发生。
这是不是一个问题取决于用户的行为。但是你应该注册onmousedown/up事件,除非你就是完全想click发生。
如果你用了弹出警示框的话,浏览器可能会丢失事件发生的轨迹和发生了多少次,会引起混乱。所以最好别用那个。
Dblclick
dblclick事件很少用。如果你要用的话一定不要把onclick和dblclick的事件处理程序注册在一个HTML元素上。如果两个都注册了的话你要知道用户到底干什么是一件基本上不可能的事情。
总之,当用户在一个元素上双击的时候click事件总是发生在dblclick之前。另外,在Netscape中,第二个click总是会在dblclick之前被分开处理。不管怎样,警示框在这是很危险的。
所以保证你的click和dblclick很好的分离能避免很多复杂的事情。
Mousemove
mousemove事件运行的很好,但是需要注意的是那可能需要很多的系统资源来处理所有的mousemove事件。当用户把鼠标移动一个像素,mousemove就触发一次。就算什么都没发生,长而复杂的函数也要耗费很长的时间会影响网站的效率:所有的事情都会变慢,尤其在那些老古董上。
所以最好的办法就是当你需要的时候注册onmousemove事件,在不用的时候尽快移除:

element.onmousemove = doSomething; 
// later 
element.onmousemove = null;

Mouseover和mouseout
再看看这个例子,换成mouserover然后试试。这个例子只是在ev3上添加了onmouseover的事件处理程序。然而你会注意到不仅仅在ev3上会触发事件在ev4或者span上都会触发。在Mozilla 1.3之前,当鼠标进入一个文本区域的时候都会触发。
原因当然就是事件冒泡。用户在ev4上触发了mouseover事件。在这个元素上没有onmouseover事件处理程序,但是在ev3上有。所以当事件冒泡到ev3上的时候,程序就执行了。
现在这样的设置虽然都完全正确,但是还有一个问题。首要问题就是目标。假设鼠标进入了ev4:
-----------------------------------------
| This is div id="ev3" |
| ----------------------------- |
| | This is div id="ev4" | |
| | -------- <-------- |
| | | span | | |

| | -------- | |
| ----------------------------- |
-----------------------------------------
<--------: mouse movement
现在这个事件的target/srcElement就是ev4:就是事件发生的元素,因为鼠标移动到了他上面。但是当下面的发生时候:
-----------------------------------------
| This is div id="ev3" |
| ----------------------------- |
| | This is div id="ev4" | |
| | -------- | |
| | | span | | |
| | | --------> | |
| | -------- | |
| ----------------------------- |
-----------------------------------------
-------->: mouse movement
这个事件的target/srcElement是一样的。在这一样还是鼠标进入ev4。然而你可能会当鼠标从ev3来或者从SPAN来的时候做不同的事。所以我们需要知道鼠标到底从哪来的。
relatedTarget,fromElement,toElement
W3C把relatedTarget属性加进了mouseover和mouseout事件中。在mouseover事件下就是包括鼠标从哪来,在mouseout下就是包括鼠标到哪去。
微软也有包含以下信息的两个属性:
1、fromElement指的是鼠标来之前的元素。在mouseover的状况下比较有用
2、toElement表示鼠标将要去的那个元素。在mouseout的情况下比较有用。
在我们的第一个例子里面,relatedTarget/fromElement包含一个ev3的引用,在我们的第二个例子是SPAN。现在你就知道鼠标的来源了。
跨浏览器的代码
所以如果你想在mouseover的情况下想知道鼠标从哪来,那么:

function doSomething(e) { 
if (!e) var e = window.event; 
var relTarg = e.relatedTarget || e.fromElement; 
}

如果在mouseout的情况下想知道鼠标的去向那么:
function doSomething(e) { 
if (!e) var e = window.event; 
var relTarg = e.relatedTarget || e.toElement; 
}

鼠标离开一个层
在一个基于层的导航菜单里面你可能需要知道鼠标什么时候离开层这样你才能把那个层关闭。所以你给这个层的onmouseout注册了一个事件处理程序。然后事件冒泡会导致当鼠标离开任意一个层的时候都会触发这个onmouseout。
--------------
| Layer |.onmouseout = doSomething;
| -------- |
| | Link | ----> We want to know about this mouseout

| -------- |
| -------- |
| | Link | |
| | ----> | but not about this one
| -------- |
--------------
---->: mouse movement
另外的一个停止的方法是当你把鼠标移入这个层,然后到了一个链接上,浏览器就在这个层上注册一个mouseout事件。这个让我很不明白(鼠标依然在层里),但是所有的浏览器都没问题。
那么我们如何在鼠标真正离开的层的时候让mouseout发生呢?

function doSomething(e) { 
if (!e) var e = window.event; 
var tg = (window.event) ? e.srcElement : e.target; 
if (tg.nodeName != 'DIV') return; 
var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement; 
while (reltg != tg && reltg.nodeName != 'BODY') 
reltg= reltg.parentNode 
if (reltg== tg) return; 
// Mouseout took place when mouse actually left layer 
// Handle event 
}

首先得到事件的target,也就是鼠标离开的元素。如果target不是DIV(层),理解结束函数,因为鼠标没有真正离开层。
如果target是层,我们不能确定鼠标时离开层了还是进入了层里面的一个链接。所以要再检查事件的relatedTarget/toElement,也就是鼠标移向的那个元素。
我们读取这个元素,然后我们通过DOM树向上遍历,直到事件的target(也就是DIV),或者BODY元素。
如果我们遇到的target是层的子元素,那么鼠标就没有离开层。就停止函数的运行。
当函数通过所有的验证我们就能确定鼠标确实离开了层,我们就能开始应该的动作了(通常是隐藏这个层)。

Mouseenter和mouseleave
微软还有个解决办法。他添加了两个新的事件mouseenter和mouseleave。除了对事件冒泡不反应以外基本上和mouseover和mouseout是一样的。他们把注册了事件的元素看成一个整块,对于发生在块内的
mouseover和mouseout不做反应。
所以这两个事件也解决了我们的问题:他们只对绑定的元素做出mouseover/out反应。
现在这两个事件只被版本在5.5以上的IE支持。或许其他浏览器哪天回借鉴下。
结尾
现在已经到了Event的介绍的尾声了。好运!
原文地址:http://www.quirksmode.org/js/events_mouse.html
我的Twitter:@rehawk

Javascript 相关文章推荐
jQuery学习笔记之DOM对象和jQuery对象
Dec 22 Javascript
JavaScript NaN和Infinity特殊值 [译]
Sep 20 Javascript
Ext中下拉列表ComboBox组件store数据格式用法介绍
Jul 15 Javascript
javascript和HTML5利用canvas构建猜牌游戏实现算法
Jul 17 Javascript
JS解决ie6下png透明的方法实例
Aug 02 Javascript
jQuery实现进度条效果代码
Dec 17 Javascript
举例讲解jQuery对DOM元素的向上遍历、向下遍历和水平遍历
Jul 07 Javascript
CSS3 3D 技术手把手教你玩转
Sep 02 Javascript
ExtJS 4.2 Grid组件单元格合并的方法
Oct 12 Javascript
详解webpack提取第三方库的正确姿势
Dec 22 Javascript
vue脚手架及vue-router基本使用
Apr 09 Javascript
apicloud拉起小程序并传递参数的方法示例
Nov 21 Javascript
JavaScript 类似flash效果的立体图片浏览器
Feb 08 #Javascript
js 省地市级联选择
Feb 07 #Javascript
js 自定义的联动下拉框
Feb 07 #Javascript
比较搞笑的js陷阱题
Feb 07 #Javascript
javascript 鼠标拖动图标技术
Feb 07 #Javascript
数组Array进行原型prototype扩展后带来的for in遍历问题
Feb 07 #Javascript
CutePsWheel javascript libary 控制输入文本框为可使用滚轮控制的js库
Feb 07 #Javascript
You might like
DISCUZ 论坛管理员密码忘记的解决方法
2009/05/14 PHP
php学习笔记之 函数声明(二)
2011/06/09 PHP
PHP实现将textarea的值根据回车换行拆分至数组
2015/06/10 PHP
Laravel 框架路由原理与路由访问实例分析
2020/04/14 PHP
两个SUBMIT按钮,如何区分处理
2006/08/22 Javascript
js判断变量是否空值的代码
2008/10/26 Javascript
js 实现打印网页中定义的部分内容的代码
2010/04/01 Javascript
JavaScript图片放大技术(放大镜)实现代码分享
2013/11/14 Javascript
用JavaScript实现类似于ListBox功能示例代码
2014/03/09 Javascript
AngularJS模块管理问题的非常规处理方法
2015/04/29 Javascript
jQuery实现不断闪烁文字的方法
2015/05/15 Javascript
纯javascript实现分页(两种方法)
2015/08/26 Javascript
BootStrapValidator校验方式
2016/12/19 Javascript
JavaScript简单验证表单空值及邮箱格式的方法
2017/01/20 Javascript
详解Angular 4 表单快速入门
2017/06/05 Javascript
Vue组件和Route的生命周期实例详解
2018/02/10 Javascript
JavaScript如何实现元素全排列实例代码
2019/05/14 Javascript
小程序调用微信支付的方法
2019/09/26 Javascript
python进阶之多线程对同一个全局变量的处理方法
2018/11/09 Python
python版本五子棋的实现代码
2018/12/11 Python
python实现电子产品商店
2019/02/26 Python
详解python tkinter模块安装过程
2020/01/06 Python
Pycharm 2020最新永久激活码(附最新激活码和插件)
2020/09/17 Python
使用Python制作一盏 3D 花灯喜迎元宵佳节
2021/02/26 Python
html5指南-6.如何创建离线web应用程序实现离线访问
2013/01/07 HTML / CSS
size?丹麦官网:英国伦敦的球鞋精品店
2019/04/15 全球购物
介绍一下Mysql的存储引擎
2015/02/12 面试题
财务部岗位职责
2013/11/19 职场文书
市场部规章制度
2014/01/24 职场文书
教育学习自我评价
2014/02/03 职场文书
2014年街道办事处工作总结
2014/12/11 职场文书
《合作意向书》怎么写?
2019/08/20 职场文书
导游词之神仙居景区
2019/11/15 职场文书
导游词之南迦巴瓦峰
2019/11/19 职场文书
MySQL8.0升级的踩坑历险记
2021/11/01 MySQL
Html5获取用户当前位置的几种方式
2022/01/18 HTML / CSS