您的位置:首页 > Web前端 > JavaScript

js 事件

2015-05-24 11:57 281 查看
今天来总结一下js事件的相关知识^_^

首先要明白什么是事件流。事件流大致分为3个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。ie8及其以下没有事件捕获阶段,只有后面两个阶段

事件捕获:事件从目标从上往下进行传播,从外往内传播。

事件冒泡:事件从目标从下往上进行传播,从内往外传播。

二者刚好相反,这样说太抽象了,下面的图片应该能直观的体现



接下来是最基本的,添加事件和删除事件

而最普通的方法如下:

var mydiv = document.getElementById("myDiv");

添加事件:
mydiv.onclick = function(){
	alert("hello world!");
}
删除事件:
mydiv.onclick = null;


下面是比较高端的用法:

addEventListener() 和 removeEventListener()

这是比较高端的用法,都需要接收3个参数,ie8及其以下不支持这种方式

第一个参数是事件的类型,第二个参数是对应的handler,第三个判断是否在冒泡阶段处理

为true,表示在捕获阶段处理, false表示在冒泡阶段处理事件

IE不支持在捕获阶段处理事件,为了兼容性考虑,通常选择在冒泡阶段处理事件

法一:
mydiv.addEventListener('click',function(){
	alert("hello world!");
}, false);
法二:
mydiv.addEventListener('click', handler, false);
function handler(){
	alert("hello world!");
}

删除事件:
mydiv.removeEventListener('click', handler, false);


只是ie8及其以下不支持这种方式,不过同时提供了另一种方式

attachEvent()和detachEvent()

mydiv.attachEvent('onclick',function(){
	alert("hello world!");
});

mydiv.attachEvent('onclick', handler);
function handler(){
	alert("hello world!");
}

删除事件:
mydiv.detachEvent('onclick', handler);


既然这里存在浏览器的兼容性问题,我们为什么不用一个方法将它们的差异封装起来,方便用户使用呢?

var EventUtil = {
	addEvent: function(element, eventType, handler){
		if(element.addEventListener){//标准浏览器
			element.addEventListener(eventType, handler, false);
		}else{
			element.attachEvent('on' + eventType, handler);
		}
	},

	removeEvent: function(element, eventType, handler){
		if(element.removeEventListener){//标准浏览器
			element.removeEventListener(eventType, handler, false);
		}else{
			element.detachEvent('on' + eventType, handler);
		}
	}
};
我们使用它的时候,这样操作就可以了:

function handler(){
	alert("hello world!");
}

function over(){
	alert("over!!!");
}

function out(){
	alert("out!!!");
}

EventUtil.addEvent(mydiv, 'click', handler);
EventUtil.addEvent(mydiv, 'mouseover', over);
EventUtil.addEvent(mydiv, 'mouseout', out);
如上面所示,大家有没有发现一个蛋疼的地方,如果我要对它添加(或删除)好几个事件,这样写起来会不会太麻烦了。我们是否能够简化它的写法呢?

那就换一种封装的方式:

var EventUtil = {
	addEvent: function(element, eventType, handler){
		var event_arr = eventType.split(' ');
		if(event_arr.length != handler.length){
			return;
		}

		for(var i = 0, len = event_arr.length; i<len; i++){
			if(element.addEventListener){//标准浏览器
				element.addEventListener(event_arr[i], handler[i], false);
			}else{
				element.attachEvent('on' + event_arr[i], handler[i]);
			}
		}
		
	},

	removeEvent: function(element, eventType, handler){
		var event_arr = eventType.split(' ');
		if(event_arr.length != handler.length){
			return;
		}

		for(var i = 0, len = event_arr.length; i<len; i++){
			if(element.removeEventListener){//标准浏览器
				element.removeEventListener(event_arr[i], handler[i], false);
			}else{
				element.detachEvent('on' + event_arr[i], handler[i]);
			}
		}
		
	}
};
这样的话就可以这样方便的使用它了:

var mydiv = document.getElementById("myDiv");

function handler(){
	alert("hello world!");
}

function over(){
	alert("over!!!");
}

function out(){
	alert("out!!!");
}

EventUtil.addEvent(mydiv, 'click mouseover mouseout', [handler, over, out]);


下面来看一下event 对象

标准浏览器中:

target 指向鼠标操作的元素;currentTarget 指向添加事件的元素,也就是this

这里有两个例子,大家可以亲手测试一下,点击的区域不同,产生的结果不一样

var mydiv = document.getElementById("myDiv");

mydiv.onclick = function(event){
	console.log(event.target === this);
	console.log(event.currentTarget === this);
	console.log(event.target === event.currentTarget);
}

document.body.onclick = function(event){
	console.log(event.target === this);
	console.log(event.currentTarget === this);
	console.log(event.target === event.currentTarget);
	console.log(event.target === mydiv);
}


下面针对事件冒泡举个例子:

var mydiv = document.getElementById("myDiv");

mydiv.onclick = function(event){
	console.log('div clicked!');
}

document.body.onclick = function(event){
	console.log('body clicked!');
}

document.getElementsByTagName('html')[0].onclick = function(event){
	console.log('html clicked!');
}
结果如下:



从这里也可以体会出事件冒泡的机理

阻止默认行为

标准浏览器是preventDefault(),IE是returnValue = false

同时这里要注意,IE和标准浏览器获取event的方式不一样

var link = document.getElementById('myLink');

标准浏览器:
link.onclick = function(event) {
	event.preventDefault();
}

IE浏览器:
link.onclick = function(event) {
	var evt = event || window.event;
	evt.preventDefault();
	evt.returnValue = false;
}


阻止冒泡

标准浏览器是stopPropagation(),IE是cancelBubble = true

标准浏览器阻止冒泡:

var mydiv = document.getElementById('myDiv');

mydiv.onclick = function(event) {
	console.log('div clicked');
	event.stopPropagation();//用来阻止冒泡
}

document.body.onclick = function(event){
	console.log('body clicked');
}

IE浏览器阻止冒泡:

var mydiv = document.getElementById('myDiv');

mydiv.onclick = function(event) {
	var evt = event || window.event;

	console.log('div clicked');
	evt.cancelBubble = true;//用来阻止冒泡
}

document.body.onclick = function(event){
	console.log('body clicked');
}


1.IE和标准浏览器在event的获取上有差异
2.IE中没有标准浏览器中的target属性,但是有srcElement属性作为替代

3.IE中阻止默认行为会用到returnValue这个属性,false则取消默认行为。标准浏览器用preventDefault()

4.IE中取消事件冒泡会用到cancelBubble这个属性,为true会取消冒泡。标准浏览器用stopPropagation()

既然IE与标准浏览器在这么多地方存在差异,我们何不将之封装起来,让用户体会不到差异不是很好吗?

var EventUtil = {
	addEvent: function(element, eventType, handler){
		var event_arr = eventType.split(' ');
		if(event_arr.length != handler.length){
			return;
		}

		for(var i = 0, len = event_arr.length; i<len; i++){
			if(element.addEventListener){//标准浏览器
				element.addEventListener(event_arr[i], handler[i], false);
			}else{
				element.attachEvent('on' + event_arr[i], handler[i]);
			}
		}
	},

	removeEvent: function(element, eventType, handler){
		var event_arr = eventType.split(' ');
		if(event_arr.length != handler.length){
			return;
		}

		for(var i = 0, len = event_arr.length; i<len; i++){
			if(element.removeEventListener){//标准浏览器
				element.removeEventListener(event_arr[i], handler[i], false);
			}else{
				element.detachEvent('on' + event_arr[i], handler[i]);
			}
		}
	},

	getEvent: function(event){
		return event || window.event;
	},

	getTarget: function(event){
		return this.getEvent(event).target || this.getEvent(event).srcElement;
	},
	//阻止默认行为
	preventDefault: function(event){
		var evt = this.getEvent(event);
		if(evt.preventDefault){//标准浏览器
			evt.preventDefault();
		}else{
			evt.returnValue = false;
		}
	},
	//阻止事件冒泡
	stopPropagation: function(event){
		var evt = this.getEvent(event);
		if(evt.stopPropagation){//标准浏览器
			evt.stopPropagation();
		}else{
			evt.cancelBubble = true;
		}
	}
};


最后简单来说说事件代理(event delegation)

通过事件代理,可以把事件处理器添加到一个父级元素上,等待一个事件从它的子级元

素里冒泡上来,并且可以得知这个事件是从哪个元素开始的。这样就避免了把事件处理器

添加到多个子级元素上,提高了性能。

比如我们有一张数据量很大的html表格,现在有一个需求,用户通过鼠标能够对每一个单元格中的数据进行更改。

如果针对很一个单元格都添加一个事件将产生很大的性能问题,甚至是浏览器崩溃。如果在这里使用事件代理,我

们只需要把事件添加到table元素上面,并且判断出是哪个单元格被操作了,然后进行相应的处理,这样会大大提高效率
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: