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 相关文章推荐
使一个函数作为另外一个函数的参数来运行的javascript代码
Aug 13 Javascript
js操作iframe兼容各种主流浏览器示例代码
Jul 22 Javascript
js表单中选择框值的获取及表单的序列化
Dec 17 Javascript
基于jquery实现表格内容筛选功能实例解析
May 09 Javascript
js完整倒计时代码分享
Sep 18 Javascript
微信小程序ibeacon三点定位详解
Oct 31 Javascript
js实现web调用摄像头 js截取视频画面
Apr 21 Javascript
这应该是最详细的响应式系统讲解了
Jul 22 Javascript
浅谈layui框架自带分页和表格重载的接口解析问题
Sep 11 Javascript
node解析修改nginx配置文件操作实例分析
Nov 06 Javascript
解决vue做详情页跳转的时候使用created方法 数据不会更新问题
Jul 24 Javascript
利用JavaScript模拟京东按键输入功能
Dec 01 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
PHP中的命名空间详细介绍
2015/07/02 PHP
php无限级评论嵌套实现代码
2018/04/18 PHP
PHP7实现和CryptoJS的AES加密方式互通示例【AES-128-ECB加密】
2019/06/08 PHP
js下用层来实现select的title提示属性
2010/02/23 Javascript
JqGrid web打印实现代码
2011/05/31 Javascript
图片img的src不变让浏览器重新加载实现方法
2013/03/29 Javascript
Extjs4中的分页应用结合前后台
2013/12/13 Javascript
jQuery使用append在html元素后同时添加多项内容的方法
2015/03/26 Javascript
jquery实现仿Flash的横向滑动菜单效果代码
2015/09/17 Javascript
Node.js中process模块常用的属性和方法
2016/12/13 Javascript
BootStrap selectpicker后台动态绑定数据的方法
2017/07/28 Javascript
ES7中利用Await减少回调嵌套的方法详解
2017/11/01 Javascript
bootstrap+spring boot实现面包屑导航功能(前端代码)
2019/10/09 Javascript
js实现带箭头的进度流程
2020/03/26 Javascript
Python中MySQL数据迁移到MongoDB脚本的方法
2016/04/28 Python
python实现计数排序与桶排序实例代码
2019/03/28 Python
Python常见数据类型转换操作示例
2019/05/08 Python
python psutil模块使用方法解析
2019/08/01 Python
Anaconda之conda常用命令介绍(安装、更新、删除)
2019/10/06 Python
Python实现我的世界小游戏源代码
2021/03/02 Python
乐天旅游台湾网站:Rakuten Travel TW
2017/06/01 全球购物
JBL英国官网:JBL UK
2018/07/04 全球购物
德国圣伯纳德草药屋:Kräuterhaus Sanct Bernhard(有中文站)
2018/08/05 全球购物
Trench London官方网站:高级风衣和意大利皮夹克
2020/07/11 全球购物
三个Unix的命令面试题
2015/04/12 面试题
五一服装活动方案
2014/01/11 职场文书
给老婆的婚前保证书
2014/02/01 职场文书
校园摄影活动策划方案
2014/02/05 职场文书
预备党员入党自我评价范文
2014/03/10 职场文书
新闻发布会策划方案
2014/06/12 职场文书
专题组织生活会方案
2014/06/15 职场文书
2015年幼儿园保育工作总结
2015/05/12 职场文书
2015年语文教学工作总结
2015/05/25 职场文书
苦儿流浪记读书笔记
2015/07/01 职场文书
人生哲理妙语30条:淡写流年,笑过人生
2019/09/04 职场文书
Nginx代理Redis哨兵主从配置的实现
2022/07/15 Servers