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数组的扩展实现代码集合
Jun 01 Javascript
JS 常用校验函数
Mar 26 Javascript
JavaScript 对话框和状态栏使用说明
Oct 25 Javascript
JavaScript 基本概念
Jan 20 Javascript
JavaScript计划任务后台运行的方法
Dec 18 Javascript
基于JQuery实现图片轮播效果(焦点图)
Feb 02 Javascript
ashx文件获取$.ajax()方法发送的数据
May 26 Javascript
js放到head中失效的原因与解决方法
Mar 07 Javascript
Vue使用vue-area-linkage实现地址三级联动效果的示例
Jun 27 Javascript
jquery图片预览插件实现方法详解
Jul 18 jQuery
vue监听滚动事件的方法
Dec 21 Vue.js
JavaScript设计模式之原型模式详情
Jun 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
基于php socket(fsockopen)的应用实例分析
2013/06/02 PHP
php面向对象中的魔术方法中文说明
2014/03/04 PHP
PHP使用CURL模拟登录的方法
2015/07/08 PHP
yii gridview实现时间段筛选功能
2017/08/15 PHP
PHP实现微信支付(jsapi支付)流程步骤详解
2018/03/15 PHP
thinkphp框架实现路由重定义简化url访问地址的方法分析
2020/04/04 PHP
Mootools 1.2教程 Fx.Tween的使用
2009/09/15 Javascript
从零开始学习jQuery (四) jQuery中操作元素的属性与样式
2011/02/23 Javascript
Javascript insertAfter() 实现函数代码
2011/10/12 Javascript
javascript学习基础笔记之DOM对象操作
2011/11/03 Javascript
最短的IE判断var ie=!-[1,]分析
2014/05/28 Javascript
javascript实现动态加载CSS
2015/01/26 Javascript
AngularJS使用ng-repeat指令实现下拉框
2016/08/23 Javascript
bootstrap学习使用(导航条、下拉菜单、轮播、栅格布局等)
2016/12/01 Javascript
浅谈JavaScript的自动垃圾收集机制
2016/12/15 Javascript
javascript兼容性(实例讲解)
2017/08/15 Javascript
如何安装控制器JavaScript生成插件详解
2018/10/21 Javascript
ES6之Proxy的get方法详解
2019/10/11 Javascript
python文件操作之目录遍历实例分析
2015/05/20 Python
详解python脚本自动生成需要文件实例代码
2017/02/04 Python
python中文件变化监控示例(watchdog)
2017/10/16 Python
TensorFlow实现简单卷积神经网络
2018/05/24 Python
Python os.rename() 重命名目录和文件的示例
2018/10/25 Python
Python学习笔记之Django创建第一个数据库模型的方法
2019/08/07 Python
基于python实现学生信息管理系统
2019/11/22 Python
Pytorch DataLoader 变长数据处理方式
2020/01/08 Python
CSS3下的渐变文字效果实现示例
2018/03/02 HTML / CSS
自主招生自荐信
2013/12/08 职场文书
客户经理岗位职责
2013/12/08 职场文书
校园之声广播稿
2014/01/31 职场文书
领导班子四风对照检查材料思想汇报
2014/09/26 职场文书
防灾减灾宣传标语
2014/10/07 职场文书
投诉书格式范本
2015/07/02 职场文书
党员心得体会范文2016
2016/01/23 职场文书
Elasticsearch 聚合查询和排序
2022/04/19 Python
SQL Server中使用表变量和临时表
2022/05/20 SQL Server