JavaScript-事件(上篇)

    事件是文档或者浏览器窗口中发生的,特定的交互瞬间。事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字。事件是javaScript和DOM之间交互的桥梁。你若触发,我便执行——事件发生,调用它的处理函数执行相应的JavaScript代码给出响应。典型的例子有:页面加载完毕触发load事件;用户单击元素,触发click事件。


事件流

    事件流描述的是从页面中接收事件的顺序。事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即DOM事件流。有两种事件流模型。

    冒泡型事件流:事件的传播是从最特定的事件目标到最不特定的事件目标。即从DOM树的叶子到根。(推荐)

    捕获型事件流:事件的传播是从最不特定的事件目标到最特定的事件目标。即从DOM树的根到叶子。

      DOM事件流:DOM标准采用捕获+冒泡。两种事件流都会触发DOM的所有对象,从document对象开始,也在document对象结束。

DOM标准规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先是事件捕获,为截获事件提供了机会,这个时候实际的目标不会接收到事件。然后是实际的目标接收到事件,并在事件处理中被看成冒泡阶段的一部分。最后一个阶段是冒泡阶段,可以在这个阶段对事件作出相应。

尽管“DOM2级事件”标准规范明确规定事件捕获阶段 不会涉及事件目标 ,但是在IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。 结果,就是有两次机会在目标对象上面操作事件。

事件处理程序

    事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字。响应某个事件的函数就叫事件处理程序(或事件侦听器)。事件处理程序的名字以"on"开头,因此click事件的事件处理程序就是onclick,load事件的事件处理程序就是onload。为事件指定事件处理程序的方式有好多种。


    HTML事件处理程序

    事件直接加在html元素上。这种方式也有两种方法,都很简单:

    第一种:直接在html中定义事件处理程序及包含的动作。onclick="alert('clicked!')"

    第二种:html中定义事件处理程序,执行的动作则调用其他地方定义的脚本。onclick="showMessage()"

    通过event变量可以直接访问事件对象,比如οnclick="alert(event.type)"会弹出click事件。在函数内部,this值等于事件的目标元素。这种方式有个明显的缺点,就是HTML与JavaScript代码紧密耦合,如果要更换事件处理程序,就要改动两个地方:HTML代码和JavaScript代码。


    DOM0级事件处理程序

    把一个函数赋值给一个事件处理程序属性。如:myBtn.onclick=function(){alert("clicked!");}

    这种方法简单而且跨浏览器,但是只能为一个元素添加一个事件处理函数。因为这种方法为元素添加多个事件处理函数,则后面的会覆盖前面的。使用DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行的,换句话说,程序中的this引用当前元素。

    删除事件处理程序myBtn.οnclick=null;


    DOM2级事件处理程序

    DOM2级事件定义了两个方法用于添加和删除事件处理程序:addEventListener()和removeEventListener()。所有的DOM节点都包含这2个方法。这两个方法都需要3个参数:事件名,事件处理函数,布尔值。这个布尔值为true,在捕获阶段处理事件,为false,在冒泡阶段处理事件,默认为false。使用DOM2级方法添加事件处理程序的主要好处是可以添加多个事件处理程序,而且按照添加的顺序触发。

    删除事件处理程序:通过addEventListener添加的事件处理程序必须通过removeEventListener删除,且参数一致。所以通过addEventListener添加的匿名函数将无法删除。

    大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。

    

    IE事件处理程序

    IE8及以下版本浏览器实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。这两个方法都需要两个参数:事件处理程序名称事件处理程序函数。由于IE8及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段。注意是事件处理程序名称而不是事件名称,所以要加上on,是onclick而不是click。

    IE事件处理程序中还有一个地方需要注意:作用域使用attachEvent()方法,事件处理程序会在全局作用域中运行,因此this等于window。而dom2或dom0级的方法作用域都是在元素内部,this值为目标元素。

    当添加多个不同的事件处理程序时,与DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。

    删除事件处理程序:通过attachEvent添加的事件处理程序必须通过detachEvent方法删除,且参数一致。

和DOM事件一样,添加的匿名函数将无法删除。

    由于这些差异,为了更好的开发,开发人员可以编写跨浏览器的事件处理程序或使用隔离浏览器差异的JavaScript库。


事件对象

    在触发DOM上的某个事件时,会产生一个事件对象event,该对象包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。例如:鼠标操作产生的event中会包含鼠标位置的信息;键盘操作产生的event中会包含与按下的键有关的信息。所有浏览器都支持event对象,但支持方式不同,在DOM中event对象必须作为唯一的参数传给事件处理函数,在IE中event是window对象的一个属性。


    DOM中的事件对象

    兼容DOM的浏览器会将一个event对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0级或DOM2级),都会传入event对象。

    在通过HTML特性指定事件处理程序时,变量event中保存着event对象。如:<input type="button" value="click" onclick="alert(event.type)"/>

    DOM0级和DOM2级事件处理程序都会把event作为参数传入。

    DOM中事件对象重要的属性:type:被触发的事件的类型;target:事件的目标。

    DOM中事件对象重要的方法:preventDefault():阻止特定事件的默认行为;stopPropagation():阻止事件冒泡。

    事件对象的eventPhase属性,可以用来确定事件当前正位于事件流的那个阶段。如果是在捕获阶段调用的事件处理程序,那么eventPhase等于1;如果事件处理程序处于目标对象上,则eventPhase等于2;如果是在冒泡阶段调用的事件处理程序,eventPhase等于3.这里要注意的是,尽管“处于目标”发生在冒泡阶段,但eventPhase任然一直等于2。

    只有在事件处理程序执行期间,event对象才会存在;一旦事件处理程序执行完成,event对象就会被销毁。


    IE中的事件对象

    在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。如果事件处理程序是使用

attachEvent()添加的,那么就会有一个event对象作为参数被传入事件处理程序函数中。如果是通过HTML特性指定的事件处理程序,那么还可以通过一个名叫event的变量来访问event对象(与DOM中的事件模型相同)。

    IE中事件对象重要的属性:type:被触发的事件的类型;srcElement:事件的目标(与DOM中的target属性相同);cancelBubble:与DOM中的stopPropagation()方法作用相同,都是用来停止事件冒泡的,设置为true即可;returnValue:与DOM中的preventDefault()方法相同,用于阻止特定事件的默认行为,设置为false即可。

    虽然DOM与IE中的event对象不同,看基于它们之间的相似性依旧可以拿出跨浏览器的方案。


事件类型

    web浏览器中可能发生事件有很多类型。如前所诉,不同的事件类型具有不同的信息,而“DOM3级事件”规定了以下几类事件:UI事件、焦点事件、鼠标事件、滚轮事件、文本事件、键盘事件、合成事件、变动事件和变动名称事件。除了这几类事件之外,HTML5也定义了一组事件,而有些浏览器还会在DOM和BOM中实现其他专有事件。这些专有事件一般都是根据开发人员需求定制的,没有什么规范,因此不同浏览器的实现有可能不一致。

    DOM3级事件模块在DOM2级事件模块基础上重新定义了这些事件,也添加了一些新事件。包括IE9在内的所有主浏览器都支持DOM2级事件。IE9支持DOM3级事件。

    

    UI事件

    UI事件指的是那些不一定与用户操作有关的事件。UI事件中主要包括load,unload,abort,error,select,resize,scroll事件。

    load事件: 这个事件是JavaScript中最常用的事件, 当页面完全加载完之后(包括所有的图像、js文件、css文件等外部资源),就会触发window上面的load事件。 比如我们经常会使用window.οnlοad=function(){};这种形式,即当页面完全加载完之后执行其中的函数。一般来说,在window上面发生的任何事件都可以在<body>元素中通过相应的特性来指定,因为在HTML中无法访问window元素。图像上面也可以触发load事件,无论是DOM中的图像还是HTML中的图像元素。当图像加载完毕后就会触发(在通过js代码新增图像节点时,新图像元素不一定要从添加到文档后才开始下载,只要设置了src属性就会开始下载)。还有一些元素也以非标准的方式支持load事件,如<script>元素和<link>元素。
    unload事件: 显然,这个事件是与load事件相对的。在文档被完全卸载后触发。用户从一个页面切换到另一个页面就会触发unload时间。利用这个事件最多的情况是清楚引用,避免内存泄漏。这个事件同样有两种方式来指定。一种是JavaScript方式,使用EventUtil.addHandler();另一种就是在body元素中添加一个特性。值得注意的是,一定要小心编写onload事件中的代码,因为它是在页面卸载后才触发,所以说页面加载后存在的那些对象,在onload触发之后就不一定存在了。
    resize事件: 当调整浏览器的窗口到一个新的宽度或高度时,就会触发resize事件。这个事件在window(窗口)上面触发。 因此同样可以通过JS或者body元素中的onresize特性来指定处理程序。浏览器窗口最小化或最大化时也会触发resize事件。
    scroll事件: 这个事件会在文档被滚动期间重复被触发,所以应当尽量保持事件处理程序的代码简单。

    焦点事件
     焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与document.hasFocus()方法及document.activeElement属性配合,可以知晓用户在页面上的行踪。主要焦点事件如下:
  • blur   在元素失去焦点时触发。这个事件不冒泡,所有浏览器都支持。
  • focus   在元素获得焦点时触发。这个事件不冒泡,所有浏览器都支持。
  • focusin  在元素获得焦点时触发。这个事件冒泡,某些浏览器不支持。
  • focusout 在元素失去焦点时触发。这个事件冒泡,某些浏览器不支持。

  注意:即使blur和focus不冒泡,也可以在捕获阶段侦听到他们。


    鼠标与轮滚事件
     鼠标事件是Web开发中最常用的一类事件,因为鼠标是最主要的定位设备。DOM3级事件中定义了9个鼠标事件,如下:
  • click---用户单击鼠标左键或按下回车键触发
  • dbclick---用户双击鼠标左键触发。
  • mousedown---在用户按下了任意鼠标按钮时触发。
  • mouseenter---在鼠标光标从元素外部首次移动到元素范围内时触发。此事件不冒泡。
  • mouseleave---元素上方的光标移动到元素范围之外时触发。不冒泡。
  • mousemove---光标在元素的内部不断的移动时触发。
  • mouseover---鼠标指针位于一个元素外部,然后用户将首次移动到另一个元素边界之内时触发。
  • mouseout---用户将光标从一个元素上方移动到另一个元素时触发。   
  • mouseup---在用户释放鼠标按钮时触发。
    页面上的所有元素都支持鼠标事件,除了 mouseenter和mouseleave外都会冒泡,也可以被取消,而取消鼠标事件将会影响浏览器的默认行为。 只有在同一个元素上相继触发mousedown和mouseup事件,才会触发click事件。同样,只有在同一个元素上触发两次click事件,才会触发dbclick事件。
    鼠标事件中还有一类滚轮事件。而说是一类事件,其实就是一个mouseWheel事件。这个事件跟踪鼠标滚轮,类似于Mac的触控板。

    客户区坐标位置: 鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的clientX 和clientY属性中。 通过客户区坐标可以知道鼠标是在视口中什么位置发生的。
    页面坐标位置: 页面坐标通过事件对象的pageX和pageY属性,能告诉你事件是在页面中的什么位置发生的。换句话说,这两个属性表示鼠标光标在页面中的位置,因此坐标是从页面本身而非视口的左边和顶边计算的。在页面没有滚动的情况下, pageX和pageY的值与clientX和clientY的值相等。 IE8及更早的浏览器是不支持事件对象上的页面坐标的,即不能通过pageX和pageY来获得页面坐标,这时 需要使用客户区坐标和滚动信息来计算了。而滚动信息需要使用document.body(混杂模式)、document.documentElement(标准模式)中的scrollLeft和scrollTop属性。
    屏幕坐标位置: 鼠标事件发生时,还有一个光标相对于整个电脑屏幕的位置。通过screenX和screenY属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的位置。
    修改键: 当点击某个元素时,如果我们同时按下了ctrl键,那么事件对象的ctrlKey属性值将为true,否则为false,对于alt、shift、meta(windows键盘的windows键、苹果机的Cmd键)的事件属性altKey、shiftKey、metaKey同样如此。
    相关元素:在发生mouseover和mouseout事件时,还会涉及更多的元素。这两个事件都会涉及把鼠标指针从一个元素的边界之内移动到另一个元素的边界之内。对mouseover事件而言,事件的主目标是获得光标的元素,而相关元素就是那个失去光标的元素。类似地,对mouseout事件而言,事件的主目标是失去光标的元素,而相关元素则是获得光标的元素。DOM通过event对象的relatedTarget属性提供了相关元素的信息。这个属性只对于mouseover和mouseout事件才包含值;对于其他事件,这个属性的值为null。IE8及之前版本不支持这个属性,但提供了保存着同样信息的不同属性。在mouseover事件触发时,IE的fromElement属性中保存了相关元素;在mouseout事件触发时,IE的toElement属性中保存着相关元素。
    鼠标按钮:只有在主鼠标按钮被单击(或键盘回车键被按下)时才会触发click事件,因此检测按钮的信息并不是必要的。但对于mousedown和mouseup事件来说,则在其event对象存在一个button属性,表示按下或释放的按钮。DOM的button属性可能有如下3个值:0表示主鼠标按钮(鼠标左键),1表示中间的鼠标按钮(鼠标滚轮按钮),2表示次鼠标按钮(鼠标右键)。但IE8及之前版本提供的button属性不太一样。
    更多的事件信息:“DOM2级事件”规范在event对象中还提供了detail属性,用于给出有关事件的更多信息。对于鼠标事件来说,detail中包含了一个数值,表示在给定位置上发生了多少次单击。IE也为鼠标事件提供了一些信息。
    鼠标滚轮事件:IE6.0首先实现了mousewheel事件。此后,Opear、Chrome和Safari也都实现了这个事件。当用户通过鼠标滚轮与页面交互、在垂直方向上滚动页面时(无论向上还是向下),就会触发mousewheel事件。这个事件可以在任何元素上面触发,最终会冒泡到document(IE8)或window(IE9、Opera、Chrome及Safari)对象。与mousewheel事件对应的event对象除包含鼠标事件的所有标准信息外,还包含一个特殊的wheelDelta属性。当用户向前滚动鼠标滚轮时,wheelDelta是120的倍数;当用户向后滚动鼠标滚轮时,wheelDelta是-120的倍数。但在Opera9.5之前的版本中,wheelDelta值的正负号是颠倒的。Firefox支持一个名为DOMMouseScroll的类似事件,也是在鼠标滚轮滚动时触发。与mousewheel事件一样,DOMMouseScroll也被视为鼠标事件,因而包含与鼠标事件有关的所有属性。而有关鼠标滚轮的信息则保存在detail属性中,当向前滚动鼠标滚轮时,这个属性的值是-3的倍数,当向后滚动鼠标的滚轮时,这个属性的值是3的倍数。
    触摸设备:IOS和Android设备的实现非常特别,因为这些设备没有鼠标。在开发时,要注意。
    无障碍性问题:不建议使用click之外的其他鼠标事件来展示功能或引发代码执行。因为这样会给盲人或视障用户造成极大不便。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值