鼠标与滚轮事件

鼠标事件是web开发中最常用的一类事件,毕竟鼠标是最主要的定位设备

DOM3级事件中定义了9个鼠标事件:

  1. click:在用户单击主鼠标按钮(一般为鼠标左键)或者按下回车时触发,这一点对确保易访问性十分重要,这意味着 onclick 事件处理程序既可以通过键盘执行也可以通过鼠标执行
  2. dbclick:在用户双击主鼠标按钮时触发(鼠标左键)。从技术上说该事件并不是DOM2级规范所支持的,但是由于浏览器对其的广泛实现在DOM3级规范中将其纳入标准
  3. mousedown:用户按下任意鼠标按钮触发,不能通过键盘触发
  4. mouseenter:鼠标光标从元素外部移入元素内部时触发,该事件不冒泡,并且在光标从元素移入元素子元素时不会触发
  5. mouseleave:光标从元素上方移出元素范围时触发,该事件不冒泡,移入后代元素不会触发
  6. mousemove:鼠标指针在元素内部移动时重复触发,不能通过键盘触发该事件
  7. mouseout:鼠标位于元素上方,此时将鼠标移至另一个元素触发,其子元素也会触发,不能通过键盘触发该事件
  8. mouseover:鼠标位于元素外部,首次移入元素范围内触发,其子元素也会触发,不能通过键盘触发该事件
  9. mouseup:用户释放鼠标按钮时触发,不能通过键盘触发

需要注意的是,页面上所有元素都支持鼠标事件。除了mouseenter和mouseleave事件,其余的鼠标事件都会冒泡,也可以被取消,取消鼠标事件会影响浏览器的默认行为

只有在同一个元素上相继触发 mousedown 和 mouseup 事件才会触发click 事件,若两者中有一者被取消,那么就不会触发click事件。

类似地,只有触发两次 click 事件才会触发一次dbclick事件(并且两次地间隔在一定时间范围内),若中途被代码取消则不会触发该事件

以上四个事件的触发顺序如下:

  1. mousedown
  2. mouseup
  3. click
  4. mousedown
  5. mouseup
  6. click
  7. dbclick

显然 click、dbclick都依赖于其它先行事件的触发,而 mousedown 和 mouseup则不受其它事件的影响

检测浏览器是否支持以上事件可使用以下代码:

var isSupported = document.implementation.hasFeature("MouseEvent","3.0");

鼠标事件中还有一类滚轮事件,说是一类事件实际上就是 mousewheel 事件。该事件跟踪鼠标滚轮,以及Mac的触控面板等相似设备

客户区坐标位置

鼠标事件都是在浏览器视口的特定位置发生的

该位置信息保存在鼠标事件对象的 clientX 和 clientY 属性中

他们的值分别表示事件触发时鼠标指针在浏览器窗口中的水平坐标和垂直坐标

注意该坐标不包括浏览的的工具栏等,也就是说该坐标是浏览器可视窗口内部的坐标(相对于浏览器窗口而非文档,也就是并不表示该元素在页面中的位置)

如:

var div = document.getElementByTagName("div")[0];
div.onclick = function(event){// 此处没有对 event 对象进行兼容处理,详见之前的文章
alert("Client coordinates:"+ event.clientX +","+event.clientY);
}

页面坐标位置

通过客户区坐标可以知道鼠标事件在视口中的发生位置

而页面坐标的信息则保存在 事件对象的 pageX 和 pageY 属性中

该属性可以告知我们是事件是在页面中的什么位置发生的

因此该属性是以页面本身的左边和顶边作为参照计算的

var div = document.getElementByTagName("div")[0];
div.onclick = function(event){// 此处没有对 event 对象进行兼容处理,详见之前的文章
alert("Client coordinates:"+ event.pageX +","+event.pageY);
}

在页面没有经过滚动的情况下,页面坐标和客户区坐标是相等的

IE8及更低版本的IE不支持事件对象上的页面坐标的属性

不过我们可以通过计算的方式来获取

代码如下:

var div = document.getElementByTagName("div")[0];
div.onclick = function(event){// 此处没有对 event 对象进行兼容处理,详见之前的文章
var pageX = event.pageX;
var pageY = event.pageY;
if(pageX === undefined){
pageX = event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);
}
if(pageY===undefined){
pageY = event.clientY + (document.body.scrollTop || document.documentElement.scrollTop);
}
alert("Page coordinates:"+pageX+","+pageY);
}

屏幕坐标位置

鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置

而相对于电脑屏幕的位置信息保存在事件对象的 screenX 和 screenY 属性上

代码如下:

var div = document.getElementByTagName("div")[0];
div.onclick = function(event){// 此处没有对 event 对象进行兼容处理,详见之前的文章
alert("Screen coordinates:"+ event.screenX+","+event.screenY);
}

修改键

虽然鼠标事件主要是由鼠标来触发的,但在按下鼠标时键盘上某些键的状态也可以影响到索要采取的操作

这些键为:

  • shift
  • ctrl
  • alt
  • Meta(windows是win键苹果是CMD键)

他们经常被用于修改鼠标事件的行为

DOM为此规定了四个属性,用于表示这些修改键的状态

  1. shiftKey
  2. ctrlKey
  3. altKey
  4. metaKey

这四个属性都保存着布尔值,以表示鼠标事件触发时这些修改键的状态(true 表示按下 false 表示没有按下)

通过检测这些事件属性,我们可以更加灵活地使用鼠标事件

相关元素

在发生 mouseover 和 mouseout 事件时,除了触发元素外还会涉及更多元素

因为这两个事件都涉及从一个元素的边界之内移入另一个元素的边界之内

对mouseover 事件而言事件的主目标是 获得光标的元素 而相关元素就是那个失去光标的元素

类似的,对于mouseout 事件而言 失去光标的是主目标,而相关元素则是获得光标的元素

DOM 通过 event 对象的 relatedTarget 属性提供相关元素的信息

该属性只对 mouseout 和 mouseover 事件存在,其它事件该属性的值为 null

IE8以下不支持该属性但提供了类似的实现

兼容处理如下:

function eventFunction(e){
var events;
if(e.relatedTarget){
events.relatedTarget = e.relatedTarget;
}else if(e.toElement){
events.relatedTarget = e.toElement;
}else if(e.fromElement){
events.relatedTarget = e.fromElement;
}else{
events.relatedTarget = null;
}// 相关元素兼容
}

鼠标按钮

只有在主鼠标按钮被单击的时候才会触发click

因此检测按钮的信息不是必要的

但是对于 mousedown 和 mouseup 事件来说用户点击的是鼠标的哪一个按钮是一个比较重要的信息

所以 在其 event 对象存在一个 button 属性,表示按下或者释放的按钮

DOM中的 button 属性可能有以下3个值:

  1. 0 表示主鼠标按钮
  2. 1 表示中间鼠标按钮
  3. 2 表示次鼠标按钮

在常规设置中,主鼠标按钮一般是指鼠标左键 中鼠标按钮指鼠标滚轮,次鼠标按钮则指的是鼠标右键

需要注意的是在低版本IE中的button与DOM标准中的 button 属性存在很大差异:

  • 0:没有按下按钮
  • 1:按下鼠标主按钮
  • 2:按下鼠标次按钮
  • 3:同时按下主次按钮
  • 4:按下鼠标中键按钮
  • 5:同时按下主按钮和中间按钮
  • 6:同时按下中间按钮和次按钮
  • 7:同时按下三个按钮

两者差异的兼容可通过以下代码实现:

function getButton(event){
if(document.implementation.hasFeature("MouseEvents","2.0")){
return event.button;
}else{
switch(event.button){
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
case 6:
return 2;
case 4:
return 1;
}
}
}

更多事件信息

”DOM2级事件“规范在 event 对象中还提供了 detail 属性,用于给出有关事件的更多信息

对于鼠标事件来说,detail 包含了一个数值,表示在给定位置上发生了多少次单击

在同一个元素上相继发生一次mousedown 和 mouseup 算作发生一次单击

detail属性从1开始计数,每次单击发生后都会递增,若在mousedown和mouseup之间鼠标移动了位置则 detail 会被重置为0

鼠标滚轮事件

鼠标滚轮事件由IE6.0首先实现,此后其它浏览器也相继实现了该事件

与 mousewheel 事件对应的 event 对象除了包含鼠标事件的所有标准信息之外还包含一个特殊的 wheelDelta 属性

当用户向前(远离自己)的方向滚动滚轮时该值是120的倍数

当用户向后(靠近自己)的方向滚动滚轮时该值是-120的倍数

需要注意的是在 opera 9.5版本之前,正负号是反的

除了 opera 之外作妖的还有火狐

火狐支持一个名为 DOMMouseScroll 的类似事件,该事件也在鼠标滚轮滚动时触发

与DOM不同的地方在于,该事件的 wheelDelta的相关对应信息保存在 detail 属性中

向前滚动时该值是-3的倍数

向后滚动时是3的倍数

该事件会冒泡到window

对于滚轮事件的跨浏览器粗略实现如下:

function getWheelDelta(e){
var clients = getClient();//该方法用于获取浏览器的特性信息,详见之前的文章 https://www.cnblogs.com/lhyxq/p/10227375.html
if(e.wheelDelta){
events.wheelDelta = (clients.engine.opera && clients.engine.opera < 9.5 ? -e.wheelDelta:e.wheelDelta)
}else{
return -e.detail * 40;
}// 滚轮事件兼容
}

触摸设备

IOS和Android设备实现非常特别,因为这些设备没有鼠标

需要注意以下几点:

  • 不支持dbclick,双击会放大画面且无法修改该行为
  • 轻击可单击元素会触发mousemove事件,该操作导致内容变化则不再发生其它事件,若没有变化则会依次发生 mousedown mouseup click 事件
  • mousemove 会触发 mouseover 和 mouseout
  • 两个手指放在屏幕上滑动页面会mousewheel事件

无障碍问题

若web应用需要确保残疾人或者使用屏幕阅读器的人能够访问,使用鼠标事件就需要特别小心

因此不建议使用 click 之外的其他鼠标事件来展示功能或者引发代码执行

需注意以下三点:

  1. 不要为了加快速度而使用mousedown事件代替 click 事件,因为在屏幕阅读器无法触发该事件
  2. 不要使用 mouseover 向用户展示新选项,原因同上,无法触发
  3. 不要使用 dbclick 执行重要操作,因为键盘无法触发该事件

以上可以提升web应用对残疾人的易访问性

Javascript高级编程学习笔记(63)—— 事件(7)鼠标及滚轮事件的更多相关文章

  1. Javascript高级编程学习笔记(57)—— 事件(1)事件流

    事件 JS与HTML的交互是通过事件实现的 而事件指的就是:文档或浏览器窗口特定的交互瞬间 可以通过侦听器来预定事件,以便在事件发生时执行相应的代码 这种模式也是设计模式中的观察者模式 事件流 有了事 ...

  2. Javascript高级编程学习笔记(72)—— 模拟事件(2)IE事件模拟

    IE中的事件模拟 低版本的IE浏览器作为前端开发的一股清流,想避过都不行 虽然低版本IE正在逐步被市场淘汰,不得不承认IE8以下的浏览器依然占了不小的份额 所以这里大概介绍IE8以下的低版本IE中的事 ...

  3. Javascript高级编程学习笔记(71)—— 模拟事件(1)DOM事件模拟

    事件,指的是网页中某个特定的交互时刻 一般来说事件由浏览器厂商负责提供,一般由用户操作或者其它浏览器功能来触发 但是有一类特殊的事件,那就是由我们开发人员通过JS触发的事件 这些事件和浏览器创建的事件 ...

  4. Javascript高级编程学习笔记(70)—— 事件(14)内存和性能

    由于事件处理程序是现代的web程序交互能力的提供者 所以在日常实践中,我们免不了要向页面中添加大量的事件处理程序(不管是用于用户交互还是用于统计用户数据) 在创建GUI(图形用户界面)的语言(如C#) ...

  5. Javascript高级编程学习笔记(69)—— 事件(13)触摸与手势事件

    触摸与手势事件 由于移动设备既没有鼠标也没有键盘,所以在为移动浏览器开发交互性网页时,常规的鼠标键盘事件根本不够用 所以早期的苹果为Safari 添加了一些与触摸相关的事件 随着后面Android的W ...

  6. Javascript高级编程学习笔记(67)—— 事件(11)HTML5事件

    DOM规范没有涵盖所有浏览器支持的所有事件 而许多浏览器出于满足用户需求,或解决特殊问题的目的,实现了一些自定义事件 HTML5列出了浏览器应该支持的所有事件,这里只讨论得到浏览器完善支持的事件(并非 ...

  7. Javascript高级编程学习笔记(66)—— 事件(10)变动事件

    变动事件 DOM2级的变动事件,能在DOM中的一部分发生变化时给出提示 变动事件是为XML或HTML DOM 设计的,并不特定于某种语言 DOM2级定义了如下变动事件: DOMSubtreeModif ...

  8. Javascript高级编程学习笔记(64)—— 事件(8)键盘与文本事件

    键盘与文本事件 用户在使用键盘时会触发键盘事件 “DOM2级事件”最初规定了键盘事件,但是最后在定稿时又删除了相应内容 所以键盘事件被放入了DOM3级事件的规范中 总的来说有三个键盘事件: keydo ...

  9. Javascript高级编程学习笔记(61)—— 事件(5)UI事件

    UI事件 UI事件是指那些不一定与用户操作有关的事件 这些事件在DOM规范出现之前,都是以各种不同的形式存在于不同的浏览器 而在DOM事件中为了保证向后兼容,现有的UI事件如下: DOMActivat ...

随机推荐

  1. 关于为什么会涉足easyui

    之前公司需要做一款类似于报价系统的功能,涉及到表单以及报表的统计, 这时分配给我,PHP也要开始弄easyui了 就这样走上了前端的路? 还挺感谢这些时间,有精力来学习额外的东西 不学习就会落后,ヾ( ...

  2. applium安装过程中遇到的问题及解决方法。

    1.安装appium server 之后, cmd输入appium-doctor,运行时提示'node'不是内部或外部的命令   一.提示'node'不是内部或外部命令,先按照下面步骤操作: 1.设置 ...

  3. boost Asio网络编程简介

    :first-child { margin-top: 0px; } .markdown-preview:not([data-use-github-style]) h1, .markdown-previ ...

  4. 服务管理之samba

    目录 samba 1.samba的简介 2. samba访问 1.搭建用户认证共享服务器 2.搭建匿名用户共享服务器 samba 1.samba的简介 Samba是在Linux和UNIX系统上实现SM ...

  5. 2018上IEC计算机高级语言(C)作业 第3次作业_说明

    一.博客作业内容 2018上IEC计算机高级语言(C)作业 第3次作业 二.评分规则说明 1.程序调试题,要描述出调试所遇到问题及修改内容,并表述清楚程序功能.流程图不规范的会减1-2分: 2.知识点 ...

  6. squid 透明代理配置

    阿铭在教程中已经介绍过squid的安装和配置,http://study.lishiming.net/chapter22.html 教程中只介绍了初级的正向代理和反向代理,这篇文档将要介绍透明代理如何配 ...

  7. kettle连接oracle报错oracle.i18n.text.converter.CharacterConverter.OGS.getInstance(I)Loracle/i18n/text/converter/CharacterConverter

    问题背景1:需要将一张excel中的数据导入到数据库中,并且还有关联转换和去重的处理问题,且此excel表不是固定的,需要写一个脚本 当新的excel拿来的时候,可以直接导入即可.所以我想用kettl ...

  8. 每日一练ACM 2019.0416

    2019.04.16     Problem Description Your task is to Calculate the sum of some integers.   Input Input ...

  9. Codeforces 1120 简要题解

    文章目录 A题 B题 C题 D题 E题 F题 传送门 A题 传送门 题意简述:给你一个mmm个数的数列,现在规定把一个数列的1,2,...,k1,2,...,k1,2,...,k分成第一组,把k+1, ...

  10. Effective Java -- 使可变性最小化

    为了使类成为不可变的,应该遵循以下五条原则: 1. 不要提供任何会下盖对象状态的方法 2. 保证类不会被扩展 3. 使所有的域都是final的 4. 使所有的域都成为私有的 5. 确保对于任何可变组件 ...