JS 事件学习笔记(一)

一 事件流

如果说某个元素有祖先元素,其祖先元素和它都定义了相同的事件,那么在该元素上发生某个事件的时候,涉及到事件在该元素和祖先元素间的传递顺序问题。
分为两种:
事件冒泡:从最具体的元素开始接收,执行事件处理程序,然后把该事件往上传递一直到document对象。
如果在某个元素上触发了某个事件,则会调用其事件处理程序,若该元素没有定义事件处理程序或者事件返回true,则会交由父级对象处理,从里到外,所有父级对象的同类事件都会被激活。一直上传到document对象为止。
事件捕获:相反,从最外层的document先捕获再依次往最具体的元素传递。即内部元素中触发了某个事件后,先由外部元素”截获“该事件,并执行自己绑定的事件处理程序。再将该事件向下传递给内部元素。
通常都使用事件冒泡。

DOM2级事件流

分为三个阶段:捕获阶段、处于目标阶段(实际目标接收到事件)、事件冒泡阶段(在该阶段让具体目标对事件作出响应)。也就是说事件首先从document往下传递,一直到目标对象,然后再以起泡方式往上传递到document。但是包含元素具体在哪个阶段执行事件处理程序是由添加事件的函数的参数来设置的。也就是说父元素一定是先接收到事件的,但是不一定在截获的时候就执行。
多数支持dom事件流的浏览器都遵循规定:在捕获阶段不涉及事件目标,但chrome、Firefox、IE9等浏览器可在捕获阶段触发事件对象上的事件,结果就是有两个机会(阶段)在目标对象上操作事件。

二 事件处理程序

A. html事件处理程序

即相应某个事件的函数,以”on“开头。事件处理程序中的代码在执行时有权访问全局作用域中的任何代码。
函数中有一个不用自定义的局部变量even,即事件对象;函数中的this指向事件的目标元素。
扩展作用域:with语句
该方式的缺点p-350

B. JavaScript指定事件处理程序

1. DOM0级事件处理程序

该方式让js代码和html紧密耦合。应使用JavaScript指定事件处理程序:将函数赋值给要操作对象的事件处理程序属性。如btn.οnclick=function(){}。
注意:在JS代码运行到绑定事件前不会指定任何事件处理程序,因此若这些代码在页面中位于按钮的后面则可能在一段时间内点击按钮没有反应。
该方式指定的事件处理程序被认为是元素的方法,是在元素的作用域中运行,this引用当前元素。以该方式指定,会在事件流的冒泡阶段被处理。DOM0级在一个DOM元素上对同一种事件只支持一个事件处理程序,后面的会覆盖前面的事件处理程序(可在一个DOM元素上绑定不同的事件)。
删除绑定的事件:btn.οnclick=null

2 . DOM2级事件处理程序
为DOM结点规定了方法addEventListener()和removeEventListener()用于设置和删除事件处理程序,这两个方法都包含三个参数:

  • 参数一:指定事件名称
  • 参数二:指定事件处理程序
  • 参数三:布尔值,true表示接收该事件的对象在事件捕获阶段就调用事件处理程序,false表示接收到该事件的对象要等到在冒泡阶段才调用。例如:
//html代码
<div id="outside">I am outside
<div id="inside">I am inside</div>
</div>
//js代码
window.onload=function(){
    var outside = document.getElementById("outside");
    outside.addEventListener("click",function(){alert("I am outside")},true);//在捕获阶段就调用

    var inside = document.getElementById("inside");
    inside.addEventListener("click",function(){alert("I am inside")},true);
}

如上面的代码,外面的盒子outside的事件处理程序设置为true,则是在捕获阶段如果截获到该事件了,就立即调用其事件处理程序,也就是说如果点击了内部盒子,则输出顺序为”I am outside”,”I am inside“。
若将外部盒子的true改为false,意思是在冒泡阶段才调用处理程序,则点击内部盒子后,输出顺序为”I am inside“,”I am outside”。

该方式仍是在所依附的元素的作用域中进行。该方式的优点是可以添加多个事件(包括同名的不会被覆盖),按照添加的先后顺序执行。
注意:removeEventListener()的参数和addEventListener的相同,但是匿名函数无法移除,也就是说事件根本没有解除绑定,仍然点击有效。实际上这个函数与传入addEventListener中的匿名函数完全是两个,可通过传入持有匿名函数引用的变量来解决:
IE中只有IE9支持DOM2级方法。

<script type="text/javascript">
window.onload=function(){
    var btn = document.getElementById("show");
    var handler = function(){alert(this.value)};
    btn.addEventListener("click",handler,false);
    btn.removeEventListener("click",handler,false);
}
</script>

为了最大限度兼容各种浏览器,最好将事件处理程序添加到事件流的冒泡阶段,只在需要在事件达到目标之前截获它的时候将事件处理程序添加到捕获阶段。

3.IE事件处理程序

IE实现了两个方法:attachEvent()和detachEvent(),添加的事件处理程序被添加到冒泡阶段。与DOM0以及DOM2级的区别是事件处理程序的作用域不是其所属的元素(this==绑定事件的元素),而是全局,即this==window。同样可以为一个元素添加多个事件,但是执行的顺序是后添加的先执行。detachEvent用于解除事件,同样匿名函数参数不能解除,应当传递其引用。
IE8及以下的程序处理函数执行顺序与绑定的顺序相反,而其他IE浏览器则是正常的。

<script type="text/javascript">
window.onload=function(){
    var out = document.getElementById("outside");
    out.attachEvent("onclick",function(){alert("I am outside")}); //注意此处是“onclick”而非“click”

    var inside = document.getElementById("inside");
    inside.attachEvent("onclick",function(){alert("I am inside")});
}
</script>

4.跨浏览器事件处理程序

var EventUtil={
    addHandler:function(element,type,handler){
        if(element.addEventListener){  //DOM2级方法
            element.addEventListener(type,handler,false);
        }else if(element.attachEvent){ //IE方法
            element.attachEvent("on"+type,handler);
        }else{  //DOM0级
            element["on"+type]=handler;
        }
    },
    removeHandler:function(element,type,handler){
        if(element.removeEventListener){  
            element.removeEventListener(type,handler,false);
        }else if(element.detachEvent){ 
            element.detachEvent("on"+type,handler);
        }else{  
            element["on"+type]=null;
        }
    }
};

三 禁止事件冒泡

先说几个相关的方法和属性:

  • cancelBubble(HTML DOM Event对象的属性):如果事件句柄想阻止事件传播到包容对象,必须把该属性设为 true。
  • stopPropagation(HTML DOM Event 对象方法):终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。

可将阻止事件冒泡的程序写成下列函数:

function stopBubble(e){
    if(e && e.stopPropagation){
        e.stopPropagation(); //DOM
    }else{
        window.even.cancelBubble=true; //IE
    }
}

把这个stopBubble(e)函数放到你想要的阻止事件冒泡函数里面就可以阻止事件冒泡了。

四 事件对象

1. DOM事件对象

在现代浏览器中,会为事件处理程序传入一个event对象作为参数,而IE浏览器按DOM0级方式绑定事件时,event是window对象的属性,而按照其他方式则是事件处理函数的参数。
不同的事件具有不同的属性和方法,但在现代浏览器中,所有事件对象都具有下列属性和方法:

  • currentTarget属性:事件处理程序正在处理事件的那个元素(即正在调用事件处理程序的元素),this始终等于currentTarget。而target属性指向最具体的那个目标,即实际被触发了事件的那个元素。
<script type="text/javascript">
var outside = document.getElementById("outside");
var inside = document.getElementById("inside");
outside.onclick=function(event){ //传递event参数
    alert("I am outside");
    alert("this==event.currentTarget? " + (this===event.currentTarget)); //+优先级高于===
    alert("event.target==this? " + (event.target===this));
    alert("event.target==inside? " + (event.target===inside));
};
inside.onclick=function(event){
    alert("I am inside");
    alert("this==event.currentTarget? " + (this===event.currentTarget));
    alert("event.target==this? " + (event.target===this));
    alert("event.target==inside? "+ (event.target===inside));
};
</script>
  • type属性:事件的类型
  • preventDefault():阻止事件触发时的默认行为,例如点击超链接被页面跳转到url指定的页面。只有cancelable属性设置为true的事件才可使用该方法。
  • eventPhase属性:事件处理程序被调用时是处于哪个阶段。1为捕获阶段、2为在目标对象上、3为冒泡阶段。

event对象只有在事件处理程序运行过程中才存在,运行完毕即销毁。

2. IE中的事件对象

IE中事件对象的方式有几种,取决于添加事件的方法。如果使用DOM0级方法,则event对象作为window对象的一个属性,应当以window.event这样的方式来使用。如果使用attachEvent()方法,则event作为事件处理函数的参数,当然也可以作为window的属性。
该对象包括下列属性和方法:
- cancelBubble属性:默认为false,设为true则取消事件冒泡
- returnValue属性:默认为true,设为false则取消事件触发时的默认行为
- srcElement属性:与target相同

注意:(1)由于在IE中事件处理程序的作用域由添加它的方式来确定,如果使用DOM0级方式,则this就是调用处理程序的元素,而通过attachEvent指定,则this==window。因此,不能认为this始终会等于事件目标,使用event.srcElement指定事件目标比较保险。
(2) IE不支持事件捕获,使用cancelBubble就只能取消事件冒泡,而stopPropagation()则捕获和冒泡都可以取消。

3. 跨浏览器的事件对象

DOM和IE中的事件对象不一样,但它们有很多方法和属性是对应的。在这里将EventUtil对象增强,实现跨浏览器的事件对象和事件处理程序。

<script type="text/javascript">
var EventUtil={
    addHandler:function(element,type,handler){
        if(element.addEventListener){  //DOM2级方法
            element.addEventListener(type,handler,false);
        }else if(element.attachEvent){ //IE方法
            element.attachEvent("on"+type,handler);
        }else{  //DOM0级
            element["on"+type]=handler;
        }
    },
    removeHandler:function(element,type,handler){
        if(element.removeEventListener){  
            element.removeEventListener(type,handler,false);
        }else if(element.detachEvent){ 
            element.detachEvent("on"+type,handler);
        }else{  
            element["on"+type]=null;
        }
    },

    getEvent:function(event){ //无论如何传入event参数,IE中若通过DOM0实现则该event是undefined的
        return event? event:window.event;
    },
    getTarget:function(event){
        return event.target || event.srcElement;
    },
    preventDefault:function(event){
        if(event.preventDefault){
            event.preventDefault();
        }else{
            event.returnValue=false;
        }
    },
    stopPropagation:function(event){
        if(event.stopPropagation){
            event.stopPropagation();
        }else{
            event.cancelBubble=true;
        }
    }   
};
</script>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值