《JavaScript高级程序设计 第三版》学习笔记 (十一)事件详解

一、事件流

1.事件冒泡:事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。最早使用事件冒泡的是IE,现在绝大多数浏览器都使用冒泡。IE9、Firefox、Chrome、Safari都将事件冒泡到window。
2.事件捕获:事件捕获是由不太具体的节点先接收事件,而最具体的节点最后接收事件。顺序与事件冒泡刚好相反。IE9、Safari、Chrome、Opera都支持这种事件类型。
3.DOM2级事件:DOM2规定事件流包括三个阶段,捕获阶段,为截获事件提供了机会;实际目标接收处理阶段;冒泡阶段,可以在这个阶段对事件做响应。如果在捕获阶段,上层DOM把事件拦下,那么实际DOM的事件就不能触发。具体流程见下图。
《JavaScript高级程序设计 第三版》学习笔记 (十一)事件详解_第1张图片

二、事件处理程序

1.DOM1级,只能通过element.οnclick=function(){}这种形式添加处理,也就是说,只能像一个事件上绑定一个处理程序。
2.DOM2级,可以使用addEventListener和removeEventListener添加或删除事件处理程序。addEventListener有三个参数:事件类型、处理程序、是否在捕获阶段调用事件处理程序(默认false)。下面例子说明了第三个参数的作用。设置为true时,控制台依次输出box1到box4,说明事件处理是在捕获阶段执行的,div1先捕获到click,执行处理程序,然后div2再捕获到。设置为false时,依次输出box4到box1,即捕获阶段谁都不处理事件,最内层的div4捕获后,没有下一层了,开始处理,然后事件开始冒泡,div3开始处理。DOM2级可以在一个事件上绑定多个处理程序。removeEventListener如果第二个参数是新函数而不是之前添加的函数引用,则完全不其作用。所以如果想把事件remove掉,add的时候只能传函数引用进去。
//小实验,事件关于addEventListener的第三个参数。




addEventListener



3.老版本IE,使用attachEvent和detachEvent来添加和删除事件处理程序,因为老IE(<9)只支持事件冒泡,不支持事件捕获,所以没有第三个参数。attachEvent和addEventListener还有一个重要区别是,前者的事件类型必须含有on,而后者没有,如onclick对应click。

三、事件对象

1.每个事件处理程序,其实都是一个回调函数,回调时默认传入一个event参数,这是一个保存了事件各种信息的对象。
2.event.type表示事件的类型;event.target表示事件的对象,相当于this;这两个最为常用,尤其是在写通用事件处理程序时。
3.event.preventDefault()可以阻止事件的默认行为,比如链接在点击的时候会跳转到href标明的地址,用这个方法可以阻止这种跳转。4.event.stopPropagation()可以阻止事件在事件流中传播,下面这个例子,div3和div4的click都不会触发。
//小实验,阻止事件传播
var boxes=document.getElementsByTagName("div");
var useCapture=true;
var clickHandler=function(){
	console.log(this.id);
	if(this.id=="box2"){
		event.stopPropagation();	
	}
}
for(var n=0;n
5.在老版本IE中,如果使用element.οnclick=function(){}这种形式注册处理事件,可以通过window.event获取事件对象;使用attachEvent则和addEventListener一样,在回调函数中添加一个event形参即可。老版本IE中,event.srcElement相当于event.target;event.returnValue=false相当于event.preventDefault();event.cancelBubble=false相当于event.stopPropagation()。

四、事件类型

1.一些标准的标签有load事件,表示已经加载完成,如body、image;还有一些标签以非标准形式支持load,如script。因此,可以用这个事件判断js脚本是不是动态加载完成了。
2.焦点事件blur、focus与其他事件有一定差异,因为他们不会冒泡。focusin是focus的通用版本、focusout是blur的通用版本。
3.DOM3级将mouseenter和mouseleave纳入了规范,这两个事件不会冒泡,而且鼠标移动到后代元素上不会出发。jQuery很早就支持了这两个事件。相比mouseover和mouseout,这两个事件简直太有用、太方便了。
4.关于鼠标事件中的鼠标位置:clientX/Y是相对于可视区域左上角的坐标(不算滚动条);pageX/Y是相对于页面左上角的坐标(包含了滚动条);screenX/Y是相对于显示器左上角的坐标;offsetX/Y是相对与触发元素的左上角的坐标。

五、内存与性能

1.绑定过多是事件处理程序,必然会消耗内存,延迟整个页面响应时间。
2.解决事件过多的问题,可以使用“事件委托”。比如所有的click最终都会冒泡的document,那么理论上只要在document绑定一个click事件,整个页面的类似事件就都能处理了。这样能减少很多内存占用。不是所有事件都能使用委托,只有冒泡的才能使用,最合适做委托的有:click、mousedown、mouseup、keydown、keyup、keypress。
//小实验 事件委托
document.body.addEventListener("click",function(event){
	console.log(event.target.id);	
});
3.在不需要事件处理程序的时候,把它移除,是比较好的选择。比如一个按钮控制是否可以在canvas上通过鼠标画图,那么完全可以在按钮的click中为canvas添加或删除各种鼠标事件,而不是在canvas的鼠标事件中判断一个boolean开关是否为true。

六、自定义事件

1.可以通过event=document.createEvent(eventName)自定义事件类型,创建后会产生一个initEventName方法。
2.通过event.initEventName()初始化事件对象。
3.通过element.dispatchEvent(event)触发事件。
//小实验 自定义事件
var div=document.getElementById("box1");
div.addEventListener("mousemove",function(event){//触发自定义事件
	if(event.offsetX<10 && event.offsetY<10){
		var myevent=document.createEvent("CustomEvent");
		myevent.initCustomEvent(
			"MyEvent",//type
			true,//bubbles
			true,//cancelable
			{text:"hello"}//detail
		);	
		this.dispatchEvent(myevent);
	}
})
div.addEventListener("MyEvent",function(event){//处理自定义事件
	console.log(event.detail.text);
});
4.上面的例子,自定义了MyEvent事件,当鼠标移动到某个div的左上角10*10像素内时触发。

你可能感兴趣的:(JavaScript)