事件是交互体验的核心功能,非常非常重要。
事件是每一个浏览器本来就有的,我们只是给相应的事件添加了一个回调函数。
下面先看一个拖拽事件的例子来感受一下事件:
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 οnclick=“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.οnclick=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; “复制代码”); “查看纯文本代码”); “返回代码高亮”)
今天的事件只是就到这里哟~