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 混淆加密收藏
Jan 16 Javascript
一些常用的JS功能函数(2009-06-04更新)
Jun 04 Javascript
jquery插件之easing使用
Aug 19 Javascript
Javascript中产生固定结果的函数优化技巧
Jan 16 Javascript
JS实现定时页面弹出类似QQ新闻的提示框
Nov 07 Javascript
如何动态的导入js文件具体该怎么实现
Jan 14 Javascript
Javascript基础知识(二)事件
Sep 29 Javascript
深入探密Javascript数组方法
Jan 08 Javascript
如何实现JavaScript动态加载CSS和JS文件
Dec 28 Javascript
微信小程序中使用wxss加载图片并实现动画效果
Aug 13 Javascript
vue2.x 通过后端接口代理,获取qq音乐api的数据示例
Oct 30 Javascript
详解vue-router的Import异步加载模块问题的解决方案
May 13 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第一次无法获取cookie问题处理
2014/12/15 PHP
微信公众平台开发关注及取消关注事件的方法
2014/12/23 PHP
PHP实现的下载远程文件类定义与用法示例
2017/07/05 PHP
在子窗口中关闭父窗口的一句代码
2013/10/21 Javascript
JavaScript通过元素的ID和name设置样式
2014/07/08 Javascript
javascript记住用户名和登录密码(两种方式)
2015/08/04 Javascript
javascript实现dom元素可拖动
2016/03/21 Javascript
jQuery 弹出层插件(推荐)
2016/05/24 Javascript
jQuery异步提交表单的两种方式
2016/09/13 Javascript
用React实现一个完整的TodoList的示例代码
2017/10/30 Javascript
jQuery+SpringMVC中的复选框选择与传值实例
2018/01/08 jQuery
30分钟快速入门掌握ES6/ES2015的核心内容(下)
2018/04/18 Javascript
webpack4.0 入门实践教程
2018/10/08 Javascript
详解基于electron制作一个node压缩图片的桌面应用
2019/01/29 Javascript
Vue组件模板的几种书写形式(3种)
2020/02/19 Javascript
echarts实现获取datazoom的起始值(包括x轴和y轴)
2020/07/20 Javascript
Python中实现远程调用(RPC、RMI)简单例子
2014/04/28 Python
Python中random模块生成随机数详解
2016/03/10 Python
Zookeeper接口kazoo实例解析
2018/01/22 Python
在python win系统下 打开TXT文件的实例
2018/04/29 Python
python 文件查找及内容匹配方法
2018/10/25 Python
python 多进程共享全局变量之Manager()详解
2019/08/15 Python
广告学专业毕业生自荐信
2013/09/24 职场文书
应届生个人求职信模板
2013/11/26 职场文书
学校办公室主任职责
2013/12/27 职场文书
写给女生的道歉信
2014/01/14 职场文书
七年级英语教学反思
2014/01/15 职场文书
管事部库房保管员岗位职责
2014/02/21 职场文书
国际经济贸易专业自荐信
2014/06/13 职场文书
低碳日宣传活动总结
2014/07/09 职场文书
学雷锋志愿者活动方案
2014/08/21 职场文书
2015年个人现实表现材料
2014/12/10 职场文书
欠条样本
2015/07/03 职场文书
2016师德师风学习心得体会
2016/01/12 职场文书
演讲稿:​快乐,从不抱怨开始!
2019/04/02 职场文书
fastdfs+nginx集群搭建的实现
2021/03/31 Servers