ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[toc] ##事件处理程序 在`DOM`中定义了一些事件, 而响应某个事件的函数就叫事件处理程序(或事件侦听器)。事件处理程序的名字一般以“on”开头,例如:`onclick`等 ##事件冒泡与捕获 事件流指的是页面中接收事件的顺序,`IE`,火狐和`chrome`浏览器都是事件冒泡,所谓是事件冒泡指的是事件最开始由最具体的元素接收,然后逐级向上传播到不具体的节点。而事件捕获则正好相反,事件捕获是由`Netscape`提出的,事件冒泡和捕获具体如下图所示: ![](https://box.kancloud.cn/2016-05-20_573ed07bb562a.png) 虽然事件捕获是Netscape唯一支持的事件流模型,但目前IE9,火狐和谷歌也都支持这种事件流模型。 ### 事件冒泡的好处 因为事件具有冒泡机制,因此我们可以利用冒泡的原理,把事件加到父级上,触发执行效果。这样做的好处当然就是提高性能了, ``` <!doctype html> <html> <head> <meta charset="UTF-8"> <title></title> <script type="text/javascript"> window.onload = function () { var aUl = document.getElementsById("bubble"); var aLi = aUl.getElementsByTagName("li"); for(var i = 0;i<aLi.length;i++){ aLi[i].onmouseover = function () { this.style.backgroundColor = "blue"; }; ali[i].onmouseout = function () { this.style.backgroundColor = ""; } } }; </script> </head> <body> <div> <ul id = "bubble"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </div> </body> ``` 这样我们就可以做到li上面添加鼠标事件。但是如果说我们可能有很多个`li`用`for`循环的话就比较影响性能。 下面我们可以用`事件委托`的方式来实现这样的效果。`html`不变: ``` <script type="text/javascript"> window.onload = function () { var aUl = document.getElementsById("bubble"); var aLi = aUl.getElementsByTagName("li"); //不管在哪个事件中,只要你操作的那个元素就是事件源。 // ie:window.event.srcElement // 标准下:event.target aUl.onmouseover = function (ev) { var ev = ev || window.event; var target = ev.target || ev.srcElement; if(target.nodeName.toLowerCase() == "li"){ target.style.background = "blue"; } }; aUl.onmouseout = function (ev) { var ev = ev || window.event; var target = ev.target || ev.srcElement; if(target.nodeName.toLowerCase() = "li"){ target.style.background = ""; } } }; </script> ``` 那么,如何阻止事件的冒泡呢,看下面一个例子: ``` <div onclick="showMsg(this,event)" id="outSide" style="width:100px; height:100px; background:#000; padding:50px"> <div onclick="showMsg(this,event)" id="inSide" style="width:100px; height:100px; background:#CCC"></div> </div> <script type="text/javascript"> //阻止事件冒泡后,你点击灰色盒子,整个过程只弹一次对话框了(注意与默认情况对比) function showMsg(obj,e) { alert(obj.id); stopBubble(e) } //阻止事件冒泡函数 function stopBubble(e) { if (e && e.stopPropagation) e.stopPropagation() else window.event.cancelBubble=true } </script> ``` 点击黑色外围的效果图: ![](https://box.kancloud.cn/2016-05-20_573ed07bcf4e3.jpg) ##DOM 0级事件处理程序 通过`js`指定事件处理程序通常是将回调函数赋给这个事件处理程序的属性。每个元素都有自己的事件处理程序属性(属性小写,例如:`onclick`) ``` btn.onclick = function(){ console.log('hello'); }; ``` 使用DOM 0级指定的事件处理程序被认为是元素的方法。因此,this指向当前元素: ``` var btn = document.getElementById('myDiv'); //DOM上触发的事件会产生一个事件对象event btn.onclick = function (event) { alert(this.id);//myDiv }; ``` ##DOM level 1 `DOM level 1` 专注于 `HTML` 和 `XML` 文档模型。它含有文档导航和处理功能。 `DOM level 1` 于 1998 年 10 月 1 日成为 W3C 推荐标准。 第二版的工作草案在 2000 年 9 月 29 日。 值得一提的是:`DOM level 0` 并不是 W3C 规范。而仅仅是对在 `Netscape Navigator 3.0` 和 `IE 3.0` 中的等价功能性的一种定义。 ##DOM 2级事件处理程序 `DOM 2`级定义了两个方法,用于指定和删除事件处理程序的操作:`addEventListener()`和`removeEventListener()`,他们都接受三个参数: ``` 1.事件名。比如上面的click 2.作为事件处理程序的函数。 3.布尔值(true表示捕获阶段调用事件处理程序,false表示冒泡阶段) ``` 通过`Element`对象的`addEventListener`方法,也可以定义事件的回调函数。 ``` //element.addEventListener(event, function, useCapture) var btn = document.getElementById('myDiv'); btn.addEventListener('click', function () { console.log(this.id); },false); ``` ##IE中的事件处理程序 IE9之前的IE浏览器不支持`addEventListener()`和`removeEventListener()`。 与其他浏览器不同的是,IE使用的是`attachEvent()`和`detachEvent()`方法来为`DOM`添加事件处理程序,由于`IE8`及更早版本只支持事件冒泡,所以他们只接受两个参数: ``` 1、事件处理程序名称(前面要加on) 2、事件处理程序函数 ``` 使用`attachEvent()`添加的事件处理程序如下: ``` var btn = document.getElementById('myDiv'); btn.attachEvent('onclick', function () { console.log(this.id); }); ``` 值得注意的是,使用`attachEvent()`方法的情况下,事件处理程序会在全局作用域中运行,所以,此时`this`等于`window` ##事件对象 在触发`DOM`上的某个事件时,会产生一个事件对象`event`,这个对象包含着所有与事件相关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。`event`对象会被作为第一个`参数`传递给事件监听的回调函数。我们可以通过这个`event`对象来获取到大量当前事件相关的信息: ``` type (String) — 事件的名称 target (node) — 事件起源的DOM节点 currentTarget?(node) — 当前回调函数被触发的DOM节点(后面会做比较详细的介绍) bubbles (boolean) — 指明这个事件是否是一个冒泡事件(接下来会做解释) preventDefault(function) — 这个方法将阻止浏览器中用户代理对当前事件的相关默认行为被触发。比如阻止\<a\>元素的click事件加载一个新的页面 cancelable (boolean) — 这个变量指明这个事件的默认行为是否可以通过调用event.preventDefault来阻止。 stopPropagation (function) — 取消事件的进一步捕获或冒泡,bubbles为true使用这个方法 eventPhase:返回一个数字,表示事件目前所处的阶段,0为事件开始从DOM表层向目标元素传播,1为捕获阶段,2为事件到达目标元素,3为冒泡阶段。 ``` 此外,事件对象还可能拥有很多其他的属性,但是他们都是针对特定的`event`的。比如,鼠标事件包含`clientX`和`clientY`属性来表明鼠标在当前视窗的位置。 另外,`stopPropagation()`方法用于立即停止事件在DOM中的传播,即取消进一步的事件冒泡或捕获。 ``` var btn = document.getElementById('myDiv'); btn.onclick = function (event) { alert("clicked"); event.stopPropagation(); }; //避免触发在document.body上的事件处理程序 document.body.onclick = function (event) { alert("Body clicked"); }; ``` 只有在事件处理程序执行期间,`event`对象才会存在,一旦事件处理程序执行完毕,`event`对象就会自动销毁。 ### IE中的事件对象 在`DOM 0`级中添加事件处理程序时,`event`对象是作为`window`对象的一个属性存在的: ``` var btn = document.getElementById('myDiv'); btn.onclick = function (event) { var event = window.event; alert(event.type);//click }; ``` IE 的`event`对象同样也包含与创建它的事件相关的属性和方法。 ``` cancleBubble 布尔 默认值时false,但可以被设置成true来取消事件冒泡,与dom中的 stopPropagation()方法相同。 returnValue 布尔 默认值是true,当设置成false时用以取消事件的默认行为 与dom中的preventDefault()相同。 srcElement  元素   事件的目标,与dom中的target属性相同。 type     字符串 被触发的事件类型。 ``` ##click事件 当用户点击以后,`event`对象会包含以下属性。 ``` pageX,pageY:点击位置相对于html元素的坐标,单位为像素。 clientX,clientY:点击位置相对于视口(viewport)的坐标,单位为像素。 screenX,screenY:点击位置相对于设备显示屏幕的坐标,单位为设备硬件的像素 ``` ### clientX,clientY 图示:`clientX`和`clientY`,他们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标(不包含滚动条区域) ![](https://box.kancloud.cn/2016-05-20_573ed07be4f1d.jpg) 偏移量 ``` 通过以下4个属性可以取得元素的偏移量。 (1)offsetHeight:元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、(可见的)水平滚动条的高度、上边框高度和下边框高度。 (2)offsetWidth:元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、(可见的)垂直滚动条的宽度、左边框宽度和右边框宽度。 (3)offsetLeft:元素的左外边框至包含元素的左内边框之间的像素距离。 (4)offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离。 ``` ### pageX,pageY 这两个属性表示鼠标光标在页面中的位置,在页面没有滚动的情况下,`pageX`,`pageY`的值与`clientX`,`clientY`的值相等 滚动大小 滚动大小,指的是包含滚动内容的元素的大小。 ``` 以下是4个与滚动大小相关的属性。 (1)scrollHeight:在没有滚动条的情况下,元素内容的总高度。 (2)scrollWidth:在没有滚动条的情况下,元素内容的总宽度。 (3)scrollLeft:被隐藏在内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动位置。 (4)scrollTop:被隐藏在内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置。 ``` ##焦点事件 焦点事件会在页面元素获得或失去焦点时触发,有以下4个焦点事件: 1. blur:元素失去焦点时触发,该事件不冒泡 2. focus:元素获得焦点时触发。不冒泡 3. focusin:元素获得焦点时触发,冒泡 4. focusout:元素失去焦点时触发,冒泡 ##鼠标事件 DOM 3级定义了9个鼠标事件: 1. click:当用户点击鼠标主键通常是指鼠标左键或按回车键时触发。 2. dbclick:用户双击鼠标时触发 3. mousedown:当用户按下鼠标任意一个键都会触发,这个事件是不能够通过键盘触发的。 4. mousemove:当鼠标在某元素周围移动时重复触发,该事件不能通过键盘事件触发。 5. mouseout:当鼠标离开元素时触发,这个事件不能通过键盘触发。 6. mouseover:当鼠标进入元素时触发,这个事件不能够通过键盘触发。 7. mouseenter:类似“mouseover”,但不冒泡,而且当光标移到后代元素上不会触发。 8. mouseleave:类似“mouseout”,但不冒泡。在元素上方是不触发。 9. mouseup:当用户释放鼠标按键时触发,不能够通过键盘触发。 传递给鼠标事件处理程序的事件对象有clientX和clientY属性,它们指定了鼠标指针相对于包含窗口的坐标。加入窗口的滚动偏移量,就可以把鼠标位置转换成文档坐标。 ``` 页面上的所有元素都支持鼠标事件。除了`mouseenter`和`mouseleave`外,所有的事件都冒泡,并且他们的默认行为是可以被取消掉的。但取消鼠标事件的默认行为可能会影响到其他事件,因为有些鼠标事件是相互依赖的。 ##拖拉事件 (1)`drag`事件 ``` drag事件在源对象被拖拉过程中触发。 ``` (2)`dragstart`,`dragend`事件 ``` dragstart事件在用户开始用鼠标拖拉某个对象时触发,dragend事件在结束拖拉时触发。 ``` (3)`dragenter`,`dragleave`事件 ``` dragenter事件在源对象拖拉进目标对象后,在目标对象上触发。dragleave事件在源对象离开目标对象后,在目标对象上触发。 ``` (4)`dragover`事件 ``` dragover事件在源对象拖拉过另一个对象上方时,在后者上触发。 ``` (5)`drop`事件 ``` 当源对象被拖拉到目标对象上方,用户松开鼠标时,在目标对象上触发drop事件。 ```