一、描述下js里面的【事件的三个阶段】html
二、IE和W3C不一样绑定事件解绑事件的方法有什么区别,参数分别是什么,以及事件对象e有什么区别前端
三、【事件的代理/委托】的原理以及优缺点git
四、写原生js【实现事件代理】,并要求兼容浏览器github
五、事件如何派发面试
六、JS事件模型与事件流介绍一下,事件代理用过吗?自定义事件,事件广播和分发浏览器
七、如何使用事件,以及IE和标准DOM事件模型之间存在的差异。dom
当面试时,问到这些问题时,问问本身是否能答的出来?函数
无论总结什么、仍是复习什么,概念从定义出发老是没错的。在《Javascript高级程序设计》中,是这么说的"事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间",也就是说事件就是js与html之间的交互实现者。性能
而事件流描述的是从页面中接收事件的顺序。而这儿就有两种事件流,后面详述。this
能够记住这个很是了不得的demo:https://wanliyuan.github.io/blog/testFunction.html (也是网上看到的)、很是清晰得展现了三个阶段的过程。
三个阶段分别是事件捕获、处于目标阶段、事件冒泡。
DOM2级事件规定的事件流就包括这个阶段。首先先发生的是事件捕获,为截获事件提供了机会。而后就是实际的目标接收到事件,最后就是冒泡阶段,能够在这个阶段对事件做出相应。
先来知道什么是事件处理程序。
<input type="button" id="btn" value="点击" onclick="show(this)"> function show(obj){ console.log(obj.value); }
这个show就是事件处理程序/事件侦听器(-----响应事件的函数)。
其实这种方式,相信前端的小伙伴们见得太多、也写的太多了。它是在HTML中定义的事件处理程序包括了执行的具体动做,或者调用页面别的地方定义的脚本,例以下面的代码:
<input type="button" value="点击" onclick="alert(11)"> <input type="button" value="点击" onclick="show(this)"> function show(obj){ console.log(obj.value); }
可是这种方式致使html与js的代码耦合度过高,也是大多数开发人员摈弃的缘由。
经过Javascript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
var btn = document.getElementById("btn"); btn.onclick = function(){ alert(this.id); }
删除事件是:btn.onclick = null;
以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理,而且这时候的事件处理程序是在元素的做用域中进行,里面的this就是当前元素。
DOM2级事件是经过addEventListener和removeEventListener来处理指定和删除事件处理程序的操做,接受三个参数(事件名、做为事件处理程序的函数,布尔值)。布尔值为true,表示在捕获阶段调用事件处理程序,如果false,则在冒泡阶段处理。
var btn = document.getElementById("myBtn"); btn.addEventListener("click",function(){ alert(this.id); },false); btn.addEventListener("click",function(){ alert("Hello world"); },false);
大多数状况下,都是将事件处理程序添加到事件流的冒泡阶段,这样能够最大限度地兼容各类浏览器。 经过removeEventListener删除事件处理程序时,必须使用相同参数,主要是那个函数名,必须跟addEventListener同样才有效。
btn.addEventListener("click",show,false)
btn.removeEventListener("click",show,false)
IE事件处理程序跟DOM2的相似,有两个方法attachEvent和detachEvent,不过这儿的参数只有两个:事件处理程序名称与事件处理程序函数。由于IE8以及更早的版本只支持事件冒泡,因此经过attachEvent添加的事件处理程序都会被添加到冒泡阶段。
var btn = document.getElementById("myBtn"); btn.attachEvent("onclick",function(){ alert("clicked"); });
btn.attachEvent("onclick",function(){ alert("Hello world"); });
IE事件处理程序跟DOM2基本的区别:第一个参数是onclick、给同一个按钮添加两个不一样的事件处理程序,是以相反的顺序被触发(Hello world -> clicked)
IE事件处理程序跟DOM0基本的区别:事件处理程序的做用域是window(this==window)
经过detachEvent移除事件处理程序也同样,第二个参数要传跟attachEvent同样的名儿。
这儿的跨浏览器的处理程序,其实就是融合了DOM2级和IE的事件处理程序,以作到兼容大多数浏览器,并且只关注冒泡阶段。
var 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; } } }
事件对象就是在触发dom上事件时产生的,它包含全部与事件有关的信息,以下图。全部浏览器都支持event对象,可是支持方式不一样,全部才有三种事件对象。
一、DOM中的事件对象
兼容DOM的浏览器都会将一个event对象传入到事件处理程序中,不管是DOM0级仍是DOM2级,都会传入event对象中。
二、IE中的事件对象
与访问DOM中的event对象不一样,访问IE的event有几种方式,取决于指定事件处理程序的方法。
如果DOM0级添加事件处理程序时,event对象做为window对象的一个属性存在。
var btn = document.getElementById("myBtn"); btn.onclick = function(){ var event = window.event; alert(event.type); }
如果使用attachEvent添加,就会有event对象做为参数被传入事件处理程序函数。不过也能够经过window对象来访问event对象,跟DOM0级同样。
var btn = document.getElementById("myBtn"); btn.attachEvent("click",function(event){ alert(event.type); });
如果HTML指定事件处理程序,也还能够经过event变量访问event对象(跟DOM0级的事件模型同样)
<input type="button" value="点击" onclick="alert(event.type)">
三、跨浏览器的事件对象
var EventUtil = { addHandler:function(element,type,handler){ //省略 }, getEvent: function (event) { return event ? event : window.event; }, getTarget:function(event){ return event.target || event.srcElement; }, preventDefault:function(evnt){ if(event.preventDefault){ event.preventDefault(); }else{ event.returnValue = false; } }, removeHandler:function(element,type,handler){ //省略 }, stopPropagation:function(event) { if(event.stopPropagation){ event.stopPropagation; }else{ event.cancelBubble = true; } } }
每一个函数都是对象,都会占用内存;内存中的对象越多,性能越差。事先对指定全部事件处理程序而致使的dom访问次数,会延迟整个页面的交互就绪事件。因此就有了事件委托,对“事件处理程序过多”的解决方案是事件委托。
var item1 = document.getElementById("goSomewhere"); var item2 = document.getElementById("doSomething"); var item3 = document.getElementById("sayHi"); EventUtil.addHandler(item1,"click",function(event){ location.href = "http://www.baidu.com"; }); EventUtil.addHandler(item2,"click",function(event){ document.title = "test"; }); EventUtil.addHandler(item3,"click",function(event){ alert("Hi"); })
这个是给三个li添加事件处理程序,经过事件委托的以下:
var list = document.getElementById("myLinks"); EventUtil.addHandler(list,"click",function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); switch(target.id){ case "goSomewhere": location.href = "http://www.baidu.com"; break; case "doSomething": document.title = "test"; break; case "sayHi": alert("Hi"); break; } })
这个就只是添加了一个事件处理程序,用来处理页面上发生的某种特定类型的事件,提高了总体性能,Live Demo。
currentTarget是事件处理程序当前正在处理的那个元素,target是事件目标。
var btn2 = document.getElementById("btn2"); btn2.onclick = function(e){ console.log(e.currentTarget==this); //true console.log(e.target==this); //true } document.body.onclick = function(e){ console.log(e.currentTarget==this); //true console.log(e.target==this); //false console.log(e.currentTarget===document.body); //false console.log(this===document.body); //false console.log(e.target===btn2); //false }