js(十四)---事件机制

事件 

    事件机制分为四个环节: 1.事件流(冒泡、捕获)2. 事件处理程序  3. 事件对象  4.事件委托

事件流


事件流:指从页面中接收事件的顺序,有冒泡流和捕获流。
当页面中发生某种事件(比如鼠标点击,鼠标滑过等)时,毫无疑问子元素和父元素都会接收到该事件,可具体顺序是怎样 的呢?冒泡和捕获则描述了两种不同的顺序。

那么冒泡和捕获十一什么样的形式发生的呢?接下来,一张图,帮助你来理解:

                                         
 
 这个图形很清楚的介绍了这个过程。


      你想一下,js的语言特点是什么就知道了,其中一个特点就是事件机制。这样你就知道,这个事件的重要性了,这也是面试老生常谈的话题。

       事件是每一个浏览器本来就有的,我们只是给相应的事件添加了一个 回调函数 。这样在触发一个函数之后,相应的会进行调用回调函数。那么该有疑问了,事件是用来做什么的,那么用一个小demo来感受一下,这个事件是用来做什么用的。

div.addEventListener('mousedown', function (e){
var disX = e.clientX - parseInt(getStyle(this, 'left')),
	disY = e.clientY - parseInt(getStyle(this, 'top'));//这是获取鼠标点跟元素最左边和最上边的距离
document.addEventListener('mousemove', mouseMove, false);//用document是有原因的,加入你拖动的比较快,会脱离这个元素,如果你用元素的话,这个元素会停止。
	div.addEventListener('mouseup', function (e) {
		document.removeEventListener('mousemove', mouseMove, false);
	}, false);
}, false);
 
function mouseMove(e) {
      div.style.left = e.clentX - disX + 'px';//
      div.style.top = e.clientY - disY + 'px';//必须要减去diX、diY,这样这个鼠标点才会在你指定的地方。
 
}
这只是一个简单的拖拽的例子。里面用到了的事件有onmousedown、onmousemove、onmouseup.这三个兄弟基本是连体的,要用一起用。


事件处理程序

事件的绑定

1.句柄方式

var div = document.getElementsByTagName('div')[0];
div.onclick = function (e) {
      console.log('a');
}
div.onclick = function(){
       console.log("b")
 }
//这样点击之后只会打印出b.

后面的这个函数就叫做事件处理函数,也称回调函数,当我们点击事件触发的时候,就会执行后面的处理函数。

事件可以持续监听,并不是执行完一次就失效,因此这个事件监听部分并不属于js引擎,因为js引擎是单线程的,事件监听属于内核的其他模块部分,一旦事件触发,事件监听就会把处理函数放入执行队列,等待js引擎来执行。

虽然句柄方式的兼容性很好,但是一个元素的一种事件只能绑定一个函数

如果用这种方式,绑定多个事件的话,前面的事件就会被覆盖掉的,所以还是相当于就绑定了一个事件。虽然说有好处,但是缺点要比好大的多。

这种方式也可以写在行间样式上面:

<div οnclick="console.log('a')"></div>
或者里面写一个函数名,在js中把这个函数给定义出来,也相当于一个执行队列,等待着被调用。

2.ele.addEventListener(type, handle, false)方法。

div.addEventListener('click', function(e) {
      console.log('a');
}, false);

这里面有三个参数,第一个参数是事件类型,第二个参数是处理函数,第三个参数是是否捕获。

当第三个对象为true时,则就变成了捕获。

处理函数可以直接在addEventListener方法里面写一个匿名函数,也可以在外面写一个命名函数,然后在放法里面写函数的引用。

这种方法更加通用常见,而且一种事件可以绑定多个函数,但是同一个处理函数只能绑定一次

 
function test1 () {
      console.log('a');
}
function test2() {
      console.log('a');
}
div.addEventListener('click', test1, false);
div.addEventListener('click', test2, false);
这样的话,这两个函数都会执行,也不会被覆盖的。

当然它也是唯一一个可以进行捕获的事件绑定的方式。但是兼容性的问题,IE9以下是不兼容的。


3.ele.attachEvent(‘on’ + type, handle)方式

这种方式是IE独有的一种方式,同样也是可以进行绑定多个回调函数的。

 
div.attachEvent('onclick', function (){
      console.log('a');
});
基本和addEventListener差不多,但是有一点区别是, 当同一个函数绑定多次的时候,addEventListener是只执行一次,但是attachEvent会绑定几次执行几次

 
function test () {
      console.log('a');
}
div.attachEvent('onclick', test);
div.attachEvent('onclick', test);
这样回打印两个a。每一种方式还是有一点不同的,所以那一种我们都必须得学习。

接下来,用的比较的多的,也是特别使用的是,在这三个时间处理中的this指向是很重要的。


1.句柄绑定方式中,函数里面的this指向元素本身

2.addEventListener方式中,函数里面的this也是指向元素本身

3.attachEvent中,函数里面的this指向的是window而不是元素本身,这算是IE的一个BUG。针对这种情况,我们就需要把函数提取出来,然后在attachEvent的时候用call来改变函数内部this的指向。

div.attachEvent('onclick', function () {
      test.call(div);
}, false);
 
有了这些作为知识点,那样的话,我们就可以封装一个函数,来做一下兼容处理:

 
	function attachEvent(ele, type, handle) {
		if (ele.addEventListener) {
			ele.addEventListener(type, handle, false);
		}else if (ele.attachEvent) {
			ele.attachEvent('on' + type, function () {
				handle.call(ele);
			});
		}else {
			ele['on' + type] = handle;
		}
	}
这样还是存在一个小问题,因为第二种方法引用了一个匿名函数,这样我们就解除不了绑定了,所以,我们得把这个匿名函数变成“有名”的不就行了吗。接下来进行优化:

 function attachevent(ele, type, handle){
            if(ele.addEventListener){
                ele.addEventListener(type, handle, false)
            }
            else if(ele.attachEvent){
                ele['similate' + type + handle] = handle;//把这个函数给保存起来
                ele[type + handle] = function(){//给匿名函数一个名字,这样就能找到
                    ele['similate' + type + handle].call(ele);//改变一下this的指向
                }
                ele.attachEvent('on' + type,ele[type + handle])//这样的绑定就可以解除了
            }
            else{
                ele['on' + type] = handle;
            }
        }

这里专门处理了IE方法中的匿名函数问题,我们用元素自身的一个属性来保存了这个处理函数。这样才是最完整的一个方法了,也是经常用的一个方法了。


有绑定,就会有解除绑定的:

1.句柄方式

ele.οnclick=null

这样很简单的就可以解除绑定的事件处理函数了。

2.ele.removeEventListener(type, handle, false)

针对的addEventListener的解除绑定。

但是这里要注意,只有命名函数才可以解除绑定,当绑定的函数是匿名函数的时候,是没有办法解除绑定的。


 
div.addEventListener('click', function (){console.log('a');}, false);
div.removeEventListener('click', function (){console.log('a');}, false);

这种形式是解除不了绑定的,刚才封装方法的时候,就特别进行优化的。

3.ele.detachEvent(‘on’ + type, handle)

针对IE的attachEvent的解除绑定。

如果不想改变this指向问题,这就无所谓了,但是想要改变this指向,就一定要注意一下了。

封装解除绑定的方法:

 
function remvoeEvent(ele, type, handle) {
      if(ele.removeEventListener) {
            ele.removeEventListener(type, handle, false);
      }else if (ele.detachEvent) {
            ele.detachEvent('on' + type, handle);
      }else {
            ele['on' + type] = null;
      }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值