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控制TR显示隐藏的几种方法
Jun 18 Javascript
JS+HTML5手机开发之滚动和惯性缓动实现方法分析
Jun 12 Javascript
jQuery Ajax前后端使用JSON进行交互示例
Mar 17 Javascript
JS自动生成动态HTML验证码页面
Jun 14 Javascript
vue.js vue-router如何实现无效路由(404)的友好提示
Dec 20 Javascript
vue 注册组件的使用详解
May 05 Javascript
vue实现文件上传功能
Aug 13 Javascript
Vue-CLI3.x 设置反向代理的方法
Dec 06 Javascript
微信小程序实现多个按钮的颜色状态转换
Feb 15 Javascript
VUE前后端学习tab写法实例
Aug 06 Javascript
原生JavaScript实现日历功能代码实例(无引用Jq)
Sep 23 Javascript
Element InputNumber 计数器的实现示例
Aug 03 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提取数据库内容中的图片地址并循环输出
2010/03/21 PHP
php教程 插件机制在PHP中实现方案
2012/11/02 PHP
PHP加密解密类实例代码
2016/07/20 PHP
PHPExcel在linux环境下导出报500错误的解决方法
2017/01/26 PHP
php适配器模式简单应用示例
2019/10/23 PHP
javascript Firefox与IE 替换节点的方法
2010/02/24 Javascript
javascript preload&amp;lazy load
2010/05/13 Javascript
JavaScript中获取未知对象属性的代码
2011/04/27 Javascript
javascript 拖动表格行实现代码
2011/05/05 Javascript
JavaScript中使用指数方法Math.exp()的简介
2015/06/15 Javascript
用move.js库实现百叶窗特效
2017/02/08 Javascript
Vue报错:Uncaught TypeError: Cannot assign to read only property’exports‘ of object’#‘的解决方法
2017/06/17 Javascript
详解Vue单元测试Karma+Mocha学习笔记
2018/01/31 Javascript
Angularjs中的$apply及优化使用详解
2018/07/02 Javascript
vue动态绑定class选中当前列表变色的方法示例
2018/12/19 Javascript
微信小程序实现页面浮动导航
2019/01/28 Javascript
Express结合Webpack的全栈自动刷新
2019/05/23 Javascript
Python的Flask框架及Nginx实现静态文件访问限制功能
2016/06/27 Python
python 上下文管理器使用方法小结
2017/10/10 Python
Python OpenCV处理图像之图像像素点操作
2018/07/10 Python
PyCharm设置每行最大长度限制的方法
2019/01/16 Python
python实现动态创建类的方法分析
2019/06/25 Python
Pycharm+django2.2+python3.6+MySQL实现简单的考试报名系统
2019/09/05 Python
TensorFlow实现批量归一化操作的示例
2020/04/22 Python
PyCharm中如何直接使用Anaconda已安装的库
2020/05/28 Python
基于python实现判断字符串是否数字算法
2020/07/10 Python
带你学习Python如何实现回归树模型
2020/07/16 Python
理解Django 中Call Stack机制的小Demo
2020/09/01 Python
HTML5 visibilityState属性详细介绍和使用实例
2014/05/03 HTML / CSS
英国和世界各地鲜花速递专家:Arena Flowers
2018/02/10 全球购物
27个经典Linux面试题及答案,你知道几个?
2014/03/11 面试题
幼师专业毕业生自荐信
2013/09/29 职场文书
毕业生找工作的自我评价
2013/10/18 职场文书
地道战观后感400字
2015/06/04 职场文书
mysql函数全面总结
2021/11/11 MySQL
使用Postman测试需要授权的接口问题
2022/06/21 Java/Android