鼠标事件是目前最常用的事件,与鼠标操作相关的事件主要有: 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.