JavaScript事件委托

参考链接:

JavaScript 事件委托详解

概念

事件委托就是把一个元素响应事件(click,keydown...)的函数委托到另一个元素。一般来讲,会把一个或一组元素的事件委托到它的父层或者更外层元素上,所以真正绑定事件的是外层元素,当时间响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件,然后在外层元素上执行函数。

事件流/事件传播

假设单击一个li标签,标签内有一个a链接

(1)DOM0:没有事件流的概念,事件不会传播

(2)IE事件流:

            #1. 事件捕捉(event capturing):单击首先发生在document上,然后逐层向下依次传递给body,列表,列表项,最终到达该链接。

            #2. 事件冒泡(event bubbling):单击首先发生在链接上,然后逐层向上冒泡,直到document对象。

(3)DOM2:比IE事件流多一个事件处理(target phase)

            #1. 事件捕捉

            #2. 事件处理

            #3. 事件冒泡


原理

事件委托就是利用事件冒泡机制实现的。

事件委托的特点:

        #1. 只需要将同类元素的事件委托给父级或者更外级的元素,不需要给所有元素都绑定事件,减少了内存占用

        #2. 动态新增的元素不用再重新绑定事件

        #3. 事件委托的实现依靠事件冒泡机制,所以不支持事件冒泡的事件不适合(Netscape只使用捕捉法)

        #4. 补充上一条,focus,blur之类的时间本身没有事件冒泡机制,无法委托;mousemove,mouseout虽然有事件冒泡,但是只能不断通过位置计算定位,对于性能消耗高,也不适合事件委托


不使用事件委托

HTML:

<body>
	<ul id="myList">
		<li id="li-1">aaa</li>
		<li id="li-2">bbb</li>
		<li id="li-3">ccc</li>
	</ul>
</body>

JS:

	var myList=document.getElementById("myList");
	var li=myList.getElementsByTagName("li");

	for(var i=0;i<li.length;i++){
		li[i].οnclick=function(e){
			var e=event || window.event;  //window.event为IE兼容写法
			var target=e.target || e.srcElement;  //标准浏览器event.target,IE浏览器event.srcElement
			alert(e.target.id+': '+e.target.innerText);
		}
	}

DOM0事件存在的问题:

        #1. 给每个列表项都绑定了相同的事件,浪费了内存

        #2. 当有新元素动态添加进来的时候,需要重新给元素绑定事件


使用事件委托

同样的HTML代码,不同的是JS:

	var myList=document.getElementById("myList");
	myList.οnclick=function(e){
		var e= event||window.event;
		var target=e.target ||e.srcElement;
		switch(target.id){
			case 'li-1':
				target.style.backgroundColor='red';
				break;
			case 'li-2':
				alert('这是第二项');
				break;
			case 'li-3':
				target.style.color='blue';
				break;
			default:
				alert('你完美地避开了所有选项~');
		}
	}


jQuery中的事件委托

$('#myList').on('click','li',function(){
	alert(this.id);
});
/*   //如果绑定事件的元素内部没有子元素,则e.target等同于this,都指向事件绑定的元素,否则e.target指向该元素的子元素
$('#myList').on('click','li',function(e){
	alert(e.target.id);
});
*/

//

DOM2的事件监听器

addEventListener(事件类型[event.type],函数[handle],是否采用捕捉法[默认false,即采用冒泡机制])

attachEvent("on"+event.type , handle) (IE)

特点:

        #1. 可以为一个事件指定多个监听器函数,解决事件覆盖的问题

        #2. 监听器之间是相互独立的

        #3. IE8及以下不支持,需要使用attachEvent(event.type , handle)

        function event1(){
		alert('给ul绑定成功1');
	}
	function event2(){
		alert('给ul绑定成功2');
	}

	var ul=document.querySelector('#myList');
	ul.addEventListener('click',event1,false); 
	ul.addEventListener('mouseout',event2,false);


阻断事件传播/停止事件冒泡

会有这种情况:

当我们分别给window , document , body,p均设置click的事件监听器时,如果在p上点击,就会依次弹出p,body,document,window的事件.

方法event.stopPropagation()event.cancelBubble(后者针对的是IE8及以下浏览器)

用法  

 event.stopPropagation();   //阻止事件的进一步传播,包括冒泡和捕捉,无参数,IE8及以下不支持
 event.cancelBubble=truel   //true为阻止冒泡

实例:

HTML代码主要部分:

<body>
	<p id="para">段落</p>
</body>

JS(未阻断):

	//因为要在p标签上做事件阻断,所以把函数单独拿出来
	function handle(){
		alert('click paragraph');
	}

	//注意监听器的顺序!!!
	document.body.addEventListener('click',handle,false);

	document.body.addEventListener('click',function(){
		alert('clicked body');
	},false);

	document.addEventListener('click',function(){
		alert('clicked document');
	},false);

	window.addEventListener('click',function(){
		alert('clicked window');
	},false);

JS(阻断,这是一种兼容性写法,推荐!):

function handle(e){
	alert('click paragraph');

	//阻断事件传播
	e=event|| window.event;
	if(e.stopPropagation){
		e.stopPropagation();
	}else{
		e.cancelBubble=true;
	}
}


防止默认行为

在浏览器模型中,有些事件自身就存在一些预定义行为。例如,单击链接会载入另一个页面。在某些情况下,我们需要禁用其默认行为。

方法event.preventDefault()event.returnValue=false;(IE)

实例:禁用默认行为,单击链接后,回答一个问题“are you sure you want to follow this link?”

HTML:

<body>
	<div>
		<a href="javascript:;">链接1</a>
		<a href="javascript:;">链接2</a>
	</div>
</body>

JS(兼容性写法,推荐!):

	//这里是禁用了所有链接的默认行为
	var links=document.getElementsByTagName("a");
	for(var i=0;i<links.length;i++){
		links[i].addEventListener('click',function(e){
			e=event||window.event;
			if(!confirm('are you sure you want to follow this link?')){
				if(e.preventDefault()){
					e.preventDefault();
				}else{
					e.returnValue=false;
				}
			}
		},false);
	}


事件解绑/移除监听器

方法event.removeEventListener(event.type , handle, boolean[默认false])event.detachEvent("on"+event.type , handle)(IE)


跨浏览器的事件监听器(推荐五颗星!!

var listenerEvent={
	getEvent:function(event){
		return event||window.event; //后者为IE
	},

	getTarget:function(event){
		return event.target||event.srcElement; //后者为IE
	},

	stopPropagation:function(){
		if(event.stopPropagation()){
			event.stopPropagation();
		}else{
			event.cancelBubble=true; //IE
		}
	},

	preventDefault:function(){
		if(event.preventDefault()){
			event.preventDefault();
		}else{
			event.returnValue=false;  //IE
		}
	},

	addListener:function(element,type,handle,boolean){ 
	//第一个参数为添加监听器的对象,第二个为事件类型,第三个为函数,第四个为是否采用捕捉法(默认false,即冒泡法)
		boolean=boolean||false; //设置boolean默认值为false
		if(element.addEventListener){
			element.addListener(type,handle,boolean);
		}else if(element.attachEvent){
			element.attachEvent("on"+type,handle);  //IE,注意在事件类型前面加了on,如click,这里需要写成onclick
		}else{
			element["on"+type]=handle; //不支持以上两种写法的备用方法
		}
	},

	removeListener:function(element,type,handle,boolean){
		boolean=boolean||false; //设置boolean默认值为false
		if(element.removeListener){
			element.removeListener(type,handle,boolean);
		}else if(element.detachEvent){
			element.detachEvent("on"+type,handle); //IE,注意在事件类型前面加了on,如click,这里需要写成onclick
		}else{
			element["on"+type]=null;//不支持以上两种写法的备用方法
		}
	}
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值