JS事件绑定、冒泡/捕获、常见的兼容处理、委托、阻止默认行为和冒泡

参考个人博客:http://www.zhuzhuman.com/nav-1/type-1/article/17.html

1. 事件绑定

      我们常见的事件一般是类似obj.onclick = function () {};这种,这种情况下,如果给同一个obj写同一个事件,那后面写的事件会把之前的事件给覆盖掉,只执行后加的事件函数。
      而事件绑定不会出现这种情况,用事件绑定方式给同一个对象加同一个事件,多次绑定的事件对应的事件函数都会执行。

IE8及以下:
	事件绑定:attachEvent("on"事件名称,事件函数);
	解除绑定:detachEvent("on"事件名称,事件函数);
	ps:上面的'"on"事件名称'是指:类似onclick、onmouseup这种 on+事件名称 的写法。默认是冒泡阶段执行。
		
Dom主流浏览器:
	事件绑定:addEventListener(事件名称,事件函数,捕获/冒泡);	
	解除绑定:removeEventListener(事件名称,事件函数,捕获/冒泡);
	ps:这里的'事件名称'是指:类似click、mouseup这种不加'on',直接写事件名的写法。'捕获/冒泡'是指:绑定的事件是在捕获还是冒泡阶段执行,该值为布尔值,捕获为true,冒泡为false,默认是false冒泡。
		
兼容方法:
	if (x.addEventListener) {//所有主流浏览器,除了 IE 8 及更早 IE版本
	    x.addEventListener("click", myFunction);
	} else if (x.attachEvent) { // IE 8 及更早 IE 版本
	    x.attachEvent("onclick", myFunction);
	}
		
注:为了移除方便,可将事件函数赋值给一个变量,然后在绑定时候,将该变量写进里面,这样移除时可以直接指定这个变量。	
<script type="text/javascript">
	// 不用事件绑定时
	var oDiv = document.getElementById("mydiv");
	oDiv.onclick = function () {
		alert(1);
	};
	oDiv.onclick = function () {
		alert(2);
	};
	// 点击只会弹2;
</script>
<script type="text/javascript">
	// 事件绑定时
	var oDiv = document.getElementById("mydiv");
	var myFnA = function () {
		alert("a");
	};
	var myFnB = function () {
		alert("b");
	};
	oDiv.addEventListener("click",myFnA);
	oDiv.addEventListener("click",myFnB,true);
	// a和b都能弹出来,先弹a;
	// oDiv.removeEventListener("click",myFnB,true); // 不能弹出b,解除事件成功
	// oDiv.removeEventListener("click",myFnB,false); // 仍能弹出b,可见解除绑定时需要针对一样的true或false进行解除。
</script>

2. 冒泡和捕获

冒泡:
	事件由里到外传递。当一个dom节点发生事件,这个事件向父级方向传递,直到达到最顶层document(有的是window)。
	也就是说,该元素的父级也能监听的到该事件的,如果父级恰好对该事件有执行函数,那么是会触发这个函数的。执行顺序是从里到外。
捕获:
	事件由外到里传递。当一个dom节点发生事件,这个事件从顶层document(有的是window)向该dom节点方向传递,执行顺序是从外到里。
	
注:W3C中,浏览器对事件的处理是先进行捕获,再进行冒泡。事件先从顶层一级一级到事件源,然后再一级一级到顶层。
但是,针对事件源(该事件最里层的那个节点),捕获和冒泡执行顺序是谁写在前面先执行谁(事件源不分捕获冒泡先后顺序,当做普通绑定事件对待,按绑定先后执行)。
<div id="mydiv">
	<div id = "mydiv2"></div>
</div>
<script type="text/javascript">
	var oUl = document.getElementById('myul');
	var oLi = document.getElementById('li1');
	oUl.addEventListener('click',function(){
		alert(0);
		return false;
	},true);
	oLi.addEventListener('click',function(){
		alert(1);
	});
	// 给父子div绑定点击事件,分别在他们捕获和冒泡阶段触发。
	var oDiv = document.getElementById("mydiv");
	var oDiv2 = document.getElementById("mydiv2");
	oDiv.addEventListener("click",function () {alert("a");},false);
	oDiv.addEventListener("click",function () {alert("b");},true);
	oDiv2.addEventListener("click",function () {alert("c");},false);
	oDiv2.addEventListener("click",function () {alert("d");},true);
	// 点击oDiv2,弹出顺序是b、c、d、a;由a、b的顺序可知:是先捕获,再冒泡,c、d的顺序可知:事件源是oDiv2(该事件最里层是oDiv2)所以针对oDiv2的捕获和冒泡,不是先执行捕获,而是谁写在前面先执行谁。
</script>

3. 常见的兼容处理

3-1 ev和event

	e = ev || window.event;
或者 e = ev || event;
或者 e = arguments[0] || window.event;

由于不同浏览器解释js代码方式不同,当我们把触发的事件对象赋予变量e的时候,一些浏览器像火狐,是直接把事件对象作为第一个参数传进去就行,我们可以把参数写作ev,也可以用arguments[0];一些浏览器像IE、chrome这种,事件对象的定义是window.event,因为所有对象都是window的属性,因此window.event == event;

<script type="text/javascript">
	function test1 (ev) {
		var e = ev || window.event;
	};
	function test2 (ev) {
		var e = ev || event;
	};
	function test3 () {
		var e = arguments[0] || window.event; 
		// js函数,即使不传参数,但是还是有一个arguments数组用来入参,
	};
</script>

3-2 获取页面的一些值时的兼容

document.documentElement.属性 // chrome不支持
document.body.属性 // chrome能识别

<script type="text/javascript">
	var top = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop; 
	// 或者
	var scrollT = document.documentElement.scrollTop || document.body.scrollTop;
</script>
类似这样获取方式的属性还有:
	clientWidth(网页可视区宽)、
	clientHeight(网页可视区高)、
	scrollWidth(网页正文全文宽)、
	scrollHeight(网页正文全文高)、
	scrollTop(可视区到网页顶端的距离,及网页被卷去的高)、
	scrollLeft(可视区到网页左端的距离,及网页被卷去的宽)

3-3 获取最终样式的兼容

我们用js的style获取的样式只能获取标签元素的行间样式,获取不到非行间样式。如果元素样式没用行间样式定义,那要怎么获取元素的样式呢?

IE下:obj.currentStyle.属性; // ie9以下
主流浏览器:getComputedStyle(obj,null).属性;// 火狐、chrome、ie9以上。第二个参数可为任意值,一般写null就行。
<script type="text/javascript">
	function getStyle(obj,attr){
		if (obj.currentStyle) {
			return obj.currentStyle[attr];
		} else {
			return getComputedStyle(obj,null)[attr];
		};
	};
</script>

4. 事件委托

事件委托:利用冒泡的原理,把事件加在父级上来触发执行效果。
事件源:不管在哪个事件下,操作的对象就是事件源。
好处:
	1.提高性能
	2.后添加进来的元素也能加上事件
原理:给父元素添加事件监听器。当有事件触发监听器时,检查事件的来源,然后根据不同的事件源来执行相应的代码。
兼容写法:
	IE: e.srcElement
	标准:e.target
	这样获取到的是触发事件的那个对象,
事件中this指向:绑定事件的父元素。
实际使用中,可以根据触发事件的对象的一些特征来进行判定,从而执行相应的代码。
	例:可以判断nodeName;获得的是该对象元素标签的大写形式为string格式(使用时需要注意),可以用toLowerCase();转化为小写后再判断。也可以判断其他的特征,如className、其他属性等
<div id="mydiv">
	<ul>
		<li></li>
		<li></li>
	</ul>
	<span class="myspan"></span>
</div>
<script type="text/javascript">
	var oDiv = document.getElementById('mydiv');
	oDiv.addEventListener('click',function (e) {
		var e = e || event;
		var target = e.srcElement || e.target;
		if (target.nodeName == 'LI') {
			alert('点击了li');
			console.log(target); // 该li对象
			console.log(e.currentTarget); // 绑定事件的div对象,注意这里用的是e,(注意currentTarget和target的区别);
			console.log(this); // 绑定事件的div对象
		} else if (target.className == 'myspan') {
			alert('点击了span');
			console.log(target); // 该span对象
			console.log(this);// 绑定事件的div对象
		};
	});
</script>

5. 阻止默认行为和冒泡

我们有时候会遇见这样的问题:

  1. 一个submit按钮,点击会提交表单数据,但是我们不希望什么数据都能够提交,想进行一些前端校验,合法数据才能提交,不合法数据不让提交。那怎样才能阻止不合法数据提交呢?这时候就需要阻止提交行为的发生。

  2. 有时候当我们给父子元素都加了点击事件,但我们不希望点击子元素时父元素的点击事件也触发。这时候我们需要阻止冒泡行为。

    有的标签具有默认行为,比如a标签的跳转,submit的提交,这些行为在点击时会发生,我们可以在点击事件中进行阻止。

    阻止默认行为:
    1. 普通写法:return false;(高版本浏览器都支持)
    注:这句话要写在自己代码的后面。
    2. 兼容写法:
    IE: e.returnValue = false;
    w3c: e.preventDefault();

<a id="mya" href="http://www.baidu.com">百度</a>
<script type="text/javascript">
	var oA = document.getElementById('mya');
	oA.addEventListener('click',function (e) {
		var e = e || event;
		if (e.preventDefault) { // 阻止默认浏览器动作(W3C)
			e.preventDefault();
		} else { // 阻止函数器默认动作(IE)
			e.returnValue = false; 
		};				
	});
</script>
阻止冒泡:
	IE方法:e.cancelBubble = true;
	w3c方法:e.stopPropagation();
<div>
	<div id="mydiv">子div</div>
<div>
<script type="text/javascript">
	var oDiv = document.getElementById('mydiv');
	oDiv.addEventListener('click',function(e) {  
	    e = e || event;  
	    if (e.stopPropagation) { // W3C阻止冒泡方法  
	        e.stopPropagation();  
	    } else {  
	        e.cancelBubble = true; // IE阻止冒泡方法  
	    };  
	};  
</script>

平常使用过程中,如果用到阻止默认行为和冒泡较多,可以将他们封装成函数,

<script type="text/javascript">
	function preventDefa(e){ 
		var e = e || window.event;
		if (e.preventDefault) { // 阻止默认浏览器动作(W3C)
			e.preventDefault();
		} else { // 阻止函数器默认动作(IE)
			e.returnValue = false; 
		};	
	}; 

	//阻止冒泡事件的兼容性处理 
	function stopBubble(e) {
		var e = e || window.event; 
		if (e.stopPropagation) { // W3C阻止冒泡方法  
			e.stopPropagation(); 
		} else { // IE阻止冒泡方法  
			e.cancelBubble = true; 
		}; 
	}; 
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值