事件是交互体验的核心功能,非常非常重要。
事件是每一个浏览器本来就有的,我们只是给相应的事件添加了一个回调函数。
下面先看一个拖拽事件的例子来感受一下事件:
1. div.addEventListener(‘mousedown’, function (e){
2. var disX = e.clientX - parseInt(getStyle(this, ‘left’)),
3. disY = e.clientY - parseInt(getStyle(this, ‘top’));
4. document.addEventListener(‘mousemove’, mouseMove, false);
5. div.addEventListener(‘mouseup’, function (e) {
6. document.removeEventListener(‘mousemove’, mouseMove, false);
7. }, false);
8. }, false);
9.
10. function mouseMove(e) {
11. div.style.left = e.clentX - disX + ‘px’;
12. div.style.top = e.clientY - disY + ‘px’;
13.
14. }
我们首先看一下如何绑定事件,这里我们以点击事件为例。
绑定事件
1.句柄方式
1. var div = document.getElementsByTagName(‘div’)[0];
2. div.onclick = function (e) {
3. console.log(‘a’);
4. }
后面的这个函数就叫做事件处理函数,也称回调函数,当我们点击事件触发的时候,就会执行后面的处理函数。
事件可以持续监听,并不是执行完一次就失效,因此这个事件监听部分并不属于js引擎,因为js引擎是单线程的,事件监听属于内核的其他模块部分,一旦事件触发,事件监听就会把处理函数放入执行队列,等待js引擎来执行。
虽然句柄方式的兼容性很好,但是一个元素的一种事件只能绑定一个函数。
基本等同于写在行间的事件。
1. <div onclick=“console.log(‘a’)“></div>
这两种写法是一致的。
一些比较简单的函数可以用这种方式来写。
2.ele.addEventListener(type, handle, false)方法。
1. div.addEventListener(‘click’, function(e) {
2. console.log(‘a’);
3. }, false);
这里面有三个参数,第一个参数是事件类型,第二个参数是处理函数,第三个参数是是否捕获。
处理函数可以直接在addEventListener方法里面写一个匿名函数,也可以在外面写一个命名函数,然后在放法里面写函数的引用。
这种方法更加通用常见,而且一种事件可以绑定多个函数,但是同一个处理函数只能绑定一次。
1.
2. function test1 () {
3. console.log(‘a’);
4. }
5. function test2() {
6. console.log(‘a’);
7. }
8. div.addEventListener(‘click’, test1, false);
9. div.addEventListener(‘click’, test2, false);
点击一次同时打印a和b。
• 这是唯一一个有事件捕获的方法。
注意:即使函数体相同,两个函数也不是一个函数。
不过很遗憾的是,这种方法在IE9以下不兼容。
3.ele.attachEvent(‘on’ + type, handle)
这个方法是IE独有的方法,一个事件同样可以绑定多个处理函数。
1.
2. div.attachEvent(‘onclick’, function (){
3. console.log(‘a’);
4. });
基本和addEventListener差不多,但是有一点区别是,当同一个函数绑定多次的时候,addEventListener是只执行一次,但是attachEvent会绑定几次执行几次。
1.
2. function test () {
3. console.log(‘a’);
4. }
5. div.attachEvent(‘onclick’, test);
6. div.attachEvent(‘onclick’, test);
现在点击一次会打印两个a。
现在这里有一个笔试常考的绑定事件的题:使用原生js,addEventListener,为每一个li绑定一个点击事件,输出他们的顺序。
这里就要注意这个题考察的不仅仅是绑定事件,更多的是闭包的运用。
1.
2. var $Li = document.getElementsByTagName(‘li’);
3. for (var i = 0, len = $Li.length; i < len; i++) {
4. (function (n) {
5. $Li[n].addEventListener(‘click’, function () {
6. console.log(n);
7. },false);
8. } (i))
9. }
事件处理程序的运行环境
1.句柄绑定方式中,函数里面的this指向元素本身。
2.addEventListener方式中,函数里面的this也是指向元素本身。
3.attachEvent中,函数里面的this指向的是window而不是元素本身,这算是IE的一个BUG。针对这种情况,我们就需要把函数提取出来,然后在attachEvent的时候用call来改变函数内部this的指向。
1. div.attachEvent(‘onclick’, function () {
2. test.call(div);
3. }, false);
4.
有了以上的知识,我们就可以封装一个兼容性的事件绑定函数了。
1.
2. function attachEvent(ele, type, handle) {
3. if (ele.addEventListener) {
4. ele.addEventListener(type, handle, null);
5. }else if (ele.attachEvent) {
6. ele.attachEvent(‘on’ + type, function () {
7. handle.call(ele);
8. });
9. }else {
10. ele[‘on’ + type] = handle;
11. }
12. }
这样事件绑定基本就完成了,但是还可以优化一下,在第二个IE的方法中我们用了一个匿名函数,这样这个函数就无法解除绑定了,因此可以优化成命名函数。
1.
2. function attachEvent(ele, type, handle) {
3. if (ele.addEventListener) {
4. ele.addEventListener(type, handle, null);
5. }else if (ele.attachEvent) {
6. ele[‘temp’ + type + handle] = handle;
7. ele[type + handle] = function () {
8. ele[‘temp’ + type + handle].call(ele);
9. };
10. ele.attachEvent(‘on’ + type, ele[type + handle]);
11. }else {
12. ele[‘on’ + type] = handle;
13. }
14. }
这种写法应该是业内公认的事件绑定方式。这里专门处理了IE方法中的匿名函数问题,我们用元素自身的一个属性来保存了这个处理函数。
解除事件处理程序
1.句柄方式
ele.onclick=null
这样很简单的就可以解除绑定的事件处理函数了。
2.ele.removeEventListener(type, handle, false)
针对的addEventListener的解除绑定。
但是这里要注意,只有命名函数才可以解除绑定,当绑定的函数是匿名函数的时候,是没有办法解除绑定的。
1.
2. div.addEventListener(‘click’, function (){console.log(‘a’);}, false);
3. div.removeEventListener(‘click’, function (){console.log(‘a’);}, false);
这是没有办法解除绑定的,因为这是两个匿名函数。
1.
2. function test() {
3. console.log(‘a’);
4. }
5. div.addEventListener(‘click’, test, false);
6. div.removeEventListener(‘click’, test, false);
必须改成这种方式才可以解除绑定。
3.ele.detachEvent(‘on’ + type, handle)
针对IE的attachEvent的解除绑定。
也是同一个函数才可以解除绑定,匿名函数无法解除绑定。
封装兼容性的解除绑定函数:
1.
2. function remvoeEvent(ele, type, handle) {
3. if(ele.removeEventListener) {
4. ele.removeEventListener(type, handle, false);
5. }else if (ele.detachEvent) {
6. ele.detachEvent(‘on’ + type, handle);
7. }else {
8. ele[‘on’ + type] = null;
9. }
10. }
今天的事件只是就到这里哟~