事件的绑定与解除

原创
2019/01/16 17:29
阅读数 1.1K

事件是交互体验的核心功能,非常非常重要。

事件是每一个浏览器本来就有的,我们只是给相应的事件添加了一个回调函数。

下面先看一个拖拽事件的例子来感受一下事件:

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.  }

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

我们首先看一下如何绑定事件,这里我们以点击事件为例。

绑定事件

1.句柄方式

1.  var div = document.getElementsByTagName(‘div’)[0];
2.  div.onclick = function (e) {
3.        console.log(‘a’);
4.  }

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

后面的这个函数就叫做事件处理函数,也称回调函数,当我们点击事件触发的时候,就会执行后面的处理函数。

事件可以持续监听,并不是执行完一次就失效,因此这个事件监听部分并不属于js引擎,因为js引擎是单线程的,事件监听属于内核的其他模块部分,一旦事件触发,事件监听就会把处理函数放入执行队列,等待js引擎来执行。

虽然句柄方式的兼容性很好,但是一个元素的一种事件只能绑定一个函数。

基本等同于写在行间的事件。

1.  <div onclick=“console.log(‘a’)“></div>

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这两种写法是一致的。

一些比较简单的函数可以用这种方式来写。

2.ele.addEventListener(type, handle, false)方法。

1.  div.addEventListener(‘click’, function(e) {
2.        console.log(‘a’);
3.  }, false);

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这里面有三个参数,第一个参数是事件类型,第二个参数是处理函数,第三个参数是是否捕获。

处理函数可以直接在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);

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

点击一次同时打印a和b。

• 这是唯一一个有事件捕获的方法。

注意:即使函数体相同,两个函数也不是一个函数。

不过很遗憾的是,这种方法在IE9以下不兼容

3.ele.attachEvent(‘on’ + type, handle)

这个方法是IE独有的方法,一个事件同样可以绑定多个处理函数。

1.   
2.  div.attachEvent(‘onclick’, function (){
3.        console.log(‘a’);
4.  });

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

基本和addEventListener差不多,但是有一点区别是,当同一个函数绑定多次的时候,addEventListener是只执行一次,但是attachEvent会绑定几次执行几次。

1.   
2.  function test () {
3.        console.log(‘a’);
4.  }
5.  div.attachEvent(‘onclick’, test);
6.  div.attachEvent(‘onclick’, test);

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

现在点击一次会打印两个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.  }

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

事件处理程序的运行环境

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.   

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

有了以上的知识,我们就可以封装一个兼容性的事件绑定函数了。

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.      }

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这样事件绑定基本就完成了,但是还可以优化一下,在第二个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.      }

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这种写法应该是业内公认的事件绑定方式。这里专门处理了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);

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

这是没有办法解除绑定的,因为这是两个匿名函数。

1.   
2.  function test() {
3.        console.log(‘a’);
4.  }
5.  div.addEventListener(‘click’, test, false);
6.  div.removeEventListener(‘click’, test, false);

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

必须改成这种方式才可以解除绑定。

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.  }

JavaScript; “复制代码”); “查看纯文本代码”); “返回代码高亮”)

今天的事件只是就到这里哟~

展开阅读全文
打赏
0
7 收藏
分享
加载中
想转发到个人公众号,求授权
2019/01/17 17:50
回复
举报
更多评论
打赏
1 评论
7 收藏
0
分享
返回顶部
顶部