JS事件处理程序
之前一直对事件处理程序这个概念不是很清楚,正好趁着看js高程这本书,来总结一下。
事件处理程序是跨浏览器的,也就是说不通的浏览器处理事件处理程序不通(主要就是IE)。
事件处理程序,分为HTML事件处理程序,DOM0/DOM2级事件处理程序,以及IE事件处理程序。
一、什么是事件处理程序:
说起事件处理程序,需要首先理解什么是事件,事件就是用户或浏览器自身执行的某种动作。例如click,load等事件。
响应某个事件的函数就叫做事件处理程序(别名:事件侦听器)。 事件处理程序的名字是以"on"开头,所以像click的事件处理程序就是"onclick"。
load的事件处理程序就是onload。
每个事件处理程序都有一个event变量,也就是事件对象。
二、HTML事件处理程序
看下面的代码:
有两种方式处理HTML事件处理程序,第一种是直接在html标签中定义,第二中在js中写函数。
<body> <!-- 直接在html标签中写入html事件处理程序 --> <input type="button" value="Click Me" onclick="alert('clicked')"> <button onclick="showMessage(event)">show message</button> <script> // 在js中写入 function showMessage(event){ console.log(event); alert('Hello world'); } </script> </body>
HTML事件处理程序都有一个event变量,通过event可以直接访问事件对象。
HTML事件的缺点:
1、如果页面没有完全加载完毕会出错。
2、HTML与JS紧密耦合。
3、不同浏览器出现差异。
三、DOM0级事件处理程序
我们经常使用的 element.onclick = function(){},这种方式的事件处理程序就是DOM0级事件处理程序
DOM0级事件处理程序,是通过js指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
DOM0级和HTML相比,有两个优点:
1、简单
2、跨浏览器优势(所有浏览器都支持)
DOM0级事件处理程序的作用域是当前的元素,所以this指向的是当前的作用域。
<body> <button id="myButton">Click Me</button> <script> // DOM0级事件处理程序,被认为是元素的方法,所以这时事件处理程序是在当前元素的作用域下运行的。 // this指向的就是当前作用域 let myButton = document.getElementById('myButton'); myButton.onclick = function (event) { console.log(this.id);//myButton } </script> </body>
删除DOM0级事件处理程序,是把当前事件处理程序的属性的值设置为null即可。
<body> <button id="myButton">Click Me</button> <script> // DOM0级事件处理程序,被认为是元素的方法,所以这时事件处理程序是在当前元素的作用域下运行的。 // this指向的就是当前作用域 let myButton = document.getElementById('myButton'); myButton.onclick = function(event){ console.log(this.id);//myButton } // 删除DOM0级事件处理程序的方法是将事件处理程序的属性的值设置为null myButton.onclick = null; </script> </body>
四、DOM2级事件处理程序
DOM2级事件,定义了两种方方法来处理定义和删除事件处理程序:addEventListener()和removeEventListener() .
这两种方法都包含三个参数,属性名,方法,和一个boolean值。如果布尔值是false,表示在冒泡阶段调用事件处理程序,如果是true表示的是在捕获阶段处理事件处理程序。默认值是false。
DOM2级事件处理程序也DOM0级相比就是可以同时添加多个事件处理程序。
如下代码,可以为btn添加多个事件处理程序。这里我们是把函数写在监听器里面的,造成的一个问题是移除事件处理程序失效。
原因是其实在处理事件处理程序和移除事件处理程序中的两个函数不是同一个函数。
<body> <button id="btn">Click Me</button> <script> let btn = document.getElementById('btn'); btn.addEventListener('click', function(){ alert(this.id); },false); // btn.addEventListener('click', function () { // console.log(123); // },false); // 如果在监听器里面写个匿名函数,移除事件处理程序是不生效的 btn.removeEventListener('click', function(){ console.log(this.id); },false); </script> </body>
我们把上面的函数改成如下:
生效。
let handler = function () { console.log(123); }; btn.addEventListener('click', handler, false); btn.removeEventListener('click', handler, false);
五、IE事件处理程序
IE实现了与DOM中类似的两个方法,attachEvent()和detachEvent()。这两个方法接收相同的参数,事件处理程序名称和事件处理函数。
<body> <button id="btn">Click Me</button> <script> let btn = document.getElementById('btn'); // 注意这里是 on开口的事件处理程序名 btn.attachEvent('onclick', function(){ console.log(123); }); </script> </body>
在IE浏览器中使用attachEvent()和DOM0级事件处理程序的主要区别是作用域方面。DOM0级事件处理程序的作用域是在当前元素上,而attachEvent则是全局作用域,也就是说tihs指向window。
attachEvent同样也是支持处理多个事件处理程序,但是它与DOM有个明显的区别就是后定义的代码先执行。
像下面代码,先输出的是456,然后才是123
<body> <button id="btn">Click Me</button> <script> let btn = document.getElementById('btn'); // 注意这里是 on开口的事件处理程序名 btn.attachEvent('onclick', function(){ console.log(123); }); btn.attachEvent('onclick', function(){ console.log(456); }); //456 //123 </script> </body>
使用attachEvent和DOM2有同样的问题,如果把函数写在里面的话是无法取消事件监听函数的。
六、跨浏览器的事件处理程序
为了兼容IE,在开发过程中只能使用跨浏览器的事件处理程序
let EventUtil = { addHandler:function(element, type, handler){ if(element.addEventListener){ element.addEventListener(type, handler, false); }else if(element.attachEvent){ element.attachEvent('on' + type, handler); }else{ element['on' + 'type'] = handler; } }, removeHandler:function(element, type, handler){ if(element.removeEventListener){ element.removeEventListener(type, handler, false); }else if(element.detachEvent){ element.detachEvent('on' + type, handler); }else{ element['on' + type] = null; } } };
我把源码放在了github上,有兴趣的可以看下。