鼠标事件是目前最常用的事件,与鼠标操作相关的事件主要有: mousedown
, mouseup
, click
, dblclick
, contextmenu
, mousemove
, mouseover
, mouseout
。
mousedown, mouseup, click
用户点击元素触发的事件顺序为:
mousedown
,用户在该元素按下鼠标按钮;mouseup
,用户在此元素上释放按下的鼠标按钮;click
,在此元素上检测到一个mousedown
和一个mouseup
;
注意,有时用户使用鼠标执行某些操作,但并不会触发 click
事件。例如用户在链接上按下鼠标按钮,然后将鼠标从链接上移开,然后释放鼠标按钮,此时只触发了 mousedown
事件。类似地,如果用户按下鼠标按钮,则将鼠标移动到链接上,然后释放鼠标按钮,此时触发了此元素的 mouseup
事件。这两种情况下下都不会触发点击事件。
dblclick
dblclick
事件很少使用。即使使用它,也应该确保不要在同一个 HTML 元素上注册 onclick
和 ondblclick
事件处理程序。毕竟,当用户双击元素时,click
事件将发生在 dblclick
之前。
注意,取消点击事件不会影响触发 dblclick
事件。
双击事件会有一个副作用,就是双击文本会选中文本,查看更多
contextmenu
和 click
行为类似,区别在于点击鼠标左键触发 click
事件,点击鼠标右键触发该事件。
注意,该事件和 click
事件类似,也能触发 mousedown
和 mouseup
事件,并且这两个事件先于 contextmenu
事件触发。
mouseover、mouseout 与 mouseenter、mouseleave
这两组事件是成对出现,并且行为比较相似,放在一起说。
mouseover
和 mouseenter
都是鼠标进入元素的时候触发的,不同点在于,对于如下的结构:
<div class="lv1"> |
当鼠标进入 lv3
的时候,会触发单一的 mouseover
,并且 mouseover
事件会冒泡,从 lv3 -> lv2 -> lv1 -> ... -> root
这个顺序开始冒泡,如果中间事件被阻止冒泡,则后面元素不能触发这个事件;而 mouseenter
事件不会冒泡,不能取消,相反 lv1、lv2、lv3 都会触发各自的 mouseenter
事件,同时,鼠标从其后代元素移动到自身元素不会再次触发此事件。这意味着,由于层次较深,所发送的 mouseenter
事件的数量可能非常多,容易造成重大的性能问题,在这种情况下,最好监听 mouseover
事件。
mouseout
和 mouseleave
都是在鼠标离开元素的时候触发,并且它们的行为分别很类似于 mouseover
和 mouseenter
:当指针离开元素或离开其后代之一(即使指针仍在元素内)时,mouseout
将被触发,并且冒泡;当指针已经退出元素及其所有后代时,此元素的所有祖先元素触发各自的 mouseleave
事件。
看个示例:
// html |
mousemove
当在元素上方移动鼠标时,会触发 mousemove
事件。
即使用户将鼠标移动一个像素,也会触发 mousemove
事件。这会非常的影响系统的性能,最好对此事件优化去抖,同时在不使用的时候移除事件的监听,具体查看本文“其他事件 —— resize 和 scroll” 一节。
wheel
当鼠标中键滚动时,触发该事件。基本用不到,有兴趣可以去啃一下 W3C 规范 Wheel Events。
select
当文本被选中的时候,select
事件会触发。并非每个元素都能触发这个事件,在 Html5 规范里,只能在 input
和 textarea
上触发该事件。
该事件不提供获得选取内容的接口,如果想要获得选取的内容,可以使用 [document/window].getSelection().toString()
区分点击按键
鼠标事件的 which 属性区分了点击的哪个按键:
- event.which == 1: 左键
- event.which == 2: 中键
- event.which == 3: 右键
注意 通常情况下并不会用到这个属性,因为点击左键触发 click
事件,点击右键触发 contextmenu
事件,但是它们都会触发 mousedown
和 `mouseup 事件,如果使用这两个事件,可能需要注意一下是否需要区分点击的按键。
鼠标按键组合事件
鼠标事件同时也会包含按键的相关信息,常用的控制按键包括:
- altKey: 当鼠标事件触发时,如果
Alt
键被按下,则返回 true; - ctrlKey: 当鼠标事件触发时,如果
Ctrl
键被按下,则返回 true; - metaKey:
Mac
上特殊属性,等价于Windows
上的ctrlKey
,当在 Mac 上鼠标事件被触发时,如果Cmd
键被按下,则返回 true ; - shiftKey: 当鼠标事件触发时,如果
Shift
键被按下,则返回 true;
使用控制按键,可以组合出更加丰富的鼠标事件,比如下面是一个支持多选的列表,按住 ctrl
点击选项则多选,否则为单选:
<ul id="list"> |
运行结果如下:
不按 ctrl,单点 li1: li1 变红 |
注意,Mac 下不存在 Ctrl
键,需要使用 Cmd
代替,可以很容易使代码支持 Mac:
if (event.ctrlKey || event.metaKey) { |
坐标属性
这里是鼠标事件中和坐标相关的属性:
- offsetX/Y: 点击位置相对于所处元素左上角的位置;
- clientX/Y: 点击位置相对于浏览器内容区域左上角的位置;
- screenX/Y: 点击位置相对于屏幕左上角的位置;
- pageX/Y: 点击位置相对整张页面左上角的位置,
pageX/Y
与clientX/Y
一般情况下会相同,只有出现滚动条时才不一样。
这几个坐标值也没有什么难度,就是很容易混淆,可以现用现查,不再详细说明。
应用:滑动选择器
之前项目有个需求,需要滑动选择内容,项目要求鼠标在点击单元格开始选择,然后在多个单元格上滑动,直到按键松开选择结束,这实际上就是 mousedown/mouseover/mouseup
这三个事件的综合应用,这里来看一下如何实现:
首先初始化选择区域:
function DragSelector(container) { |
然后是重点,绑定事件,这个可以分解为多个任务:
1.使用 mousedown
处理点击后开始选择:
// self.draging 标识开始选择,将 |
2.使用 mouseover
处理滑动到元素后开始选择:
$(this._container).on('mouseover', 'li', function() { |
3.使用 mouseup
处理按键松开后结束选择:
$(this._container).on('mouseup', 'li', function() { |
这样就是一个简略的滑动选择器,当然没有进行复杂的处理,比如数据去重,比如反选等操作,仅做简单演示。
See the Pen NXZNeV by tcatche (@tcatche) on CodePen.