关于js中的事件

  这是第一篇技术性博客。

因为最近做的web版前端求职简历算是告一段落了(点此看简历)。(稍微记录下吧:自从确定简历的简笔画风格(因为刚开始设想的蓝天白云大树啥的不仅图片特难找而且做着做着就觉得有点俗了,简笔画这种黑白风格对PS技术要求就很低了),大概花了写这篇博客前的4、5天做好的(额,上班时间也在做,因为最近公司不忙))总之就是在做简历的过程中感觉对js事件了解多了一点,所以先记下来,以后争取能再完善。

  • 避免重复注册事件

这是我曾经在QQ群里求助的一个问题,感觉看过的书里也没有特意提到。具体来说就是一个元素相同的事件处理程序注册多次的话,每次执行时会把以前累计注册的事件都执行。这个问题在以下情况最常见:在元素aa的事件里创造了元素bb并给它添加了事件,如此一来每次a相应事件发生时都会给bb添加事件。

如#aa和#bb为兄弟节点:

$(function(){ var i=0;
    $('#aa').click(function(){
        i++;
         $('#bb').click(function(){
             alert(i);
         }) 
     })
})

如上,则第一次click #aa再click #bb时,  弹出1;

    第二次click #aa再click #bb时,连续弹出2、2;

    第三次click #aa再click #bb时,连续弹出3、3、3.

解决办法:先删除事件再添加,unbind以后再bind。

  • 重要的事件对象

我们知道在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息,包括导致事件的元素、事件类型等。其中的常用有:

1. event.type(被触发的事件的类型,如“click”);

2.event.eventPhase(调用事件处理程序的阶段:1表示捕获阶段,2表示"处于目标",3表示冒泡阶段)

3.event.target和event.currentTarget

4.event.stopPropagation()

这就涉及到事件流了,"DOM2级事件“规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。捕获阶段从document往下到目标节点的父元素就停止,然后是处于目标阶段,事件发生,在事件处理中也看成冒泡阶段的一部分,在冒泡阶段可以对事件作出响应。在事件处理程序内部,this始终等于event.currentTarget,表示注册事件的对象,而由于事件流导致冒泡阶段也会触发事件,而 event.target就表示实际事件目标。(2013-8-21添加:并不是只在冒泡阶段响应,由于Netscape和IE的事件发生顺序不同,W3C综合了二者,可以选择是在捕获阶段还是冒泡阶段绑定事件处理函数,这是通过addEventListener()方法实现的,如果这个函数的最后一个参数是true,则在捕获阶段绑定函数,反之false,在冒泡阶段绑定函数。

"DOM2级事件“中添加事件处理程序:

var btn=document.getElementById('myBtn');

btn.addEventListener("click",function(){alert(this.id);},false);

大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器,不建议事件捕获阶段注册事件处理程序。W3C默认是绑定在冒泡阶段。

比如一个元素包含一个子元素,为父元素添加事件:

    <div id='father'>
     <p id='son' >aaaaa</p>
    </div>
$('#father').click(function(event){
        console.log(event.eventPhase);    
     console.log(
"event.target:"+event.target+",event.currentTarget:"+event.currentTarget); })

在不包含son的father区域click时

2  event.target:[object HTMLDivElement],event.currentTarget:[object HTMLDivElement];

在son上click时:

3 event.target:[object HTMLParagraphElement],event.currentTarget:[object HTMLDivElement]。
这也就解释了为什么event.target的含义,有动作发生时是从document向下捕获到event.target而不是event.currentTarget,然后向上冒泡到document,在捕获阶段不触发事件。可以通过event.stopPropagation()来取消冒泡(2013-8-21添加:IE中的是event.cancelBubble()来取消事件冒泡(jQuery已经统一用event.stopPropagation()来兼容了吧);DOM中的event.preventDefault()可以用来取消默认行为,如超链接的跳转,IE中的是要设置event.returnValue=false。)。
同样是上面的两个父子节点,可以看看下面这个例子的结果:
    $('#father').click(function(event){
        alert ('father:'+event.eventPhase);
    })
    $('#son').click(function(event){
        alert ('son:'+event.eventPhase);        
    })

在不包含son的father区域click时:father:2

在son上click时:son:2 father:3

为son的click事件里添加event.stopPropagation()后就可以只son:2了。

(以上若有错恳请指正)

附注:如果想根据具体情况来执行某些语句,可以利用if(event.target == this)。或event.target.tagName.toUpperCase()来获取标签名(当然这办法对有多层子元素的很不好)。

判断一个对象是否为jQuery对象:if(obj instanceof jQuery),jQuery中比较两个对象是否为同一个对象:$('#son')==$('p')这样总是false,这样是在比较引用地址?还是jQuery没有这个办法?(

2013-8-21添加:在js中当比较两个使用值存储的数据时,若它们的值相同,等值比较的结果是true;如果比较两个使用引用存储的数据,当且仅当它们引用同一个值时,等值比较的结果才是true,比较的是引用(对应存储地址)。如

var a={x:1,y:2};

var b=a;

var c={x:1,y:2};

alert(a==b);//true

alert(a==c);//false

alert(a>=c);//不确定

)不过可以使用$(event.target).is($('p'))来判断。

  • 对含有子元素的节点对象的mouseenter、mouseleave和mouseover、mouseout

先来看一个例子:

$('#father').mouseover(function(event){
        console.log(event.target+'eovered');                  
    $('#son').text(event.target+'overed').css('background','white'); }).mouseout(function(event){ console.log(event.target+'outed'); $('#son').text(event.target+'outed').css('background','red'); })

 

结果就是几十从father移入son、从son移除father,都会触发mouseover和mouseout啊。(页面从移出到移入的瞬间太快,效果不明显,从console.log里面看啊),这样是不是很烦哪?

如果你试试把mouseover和mouseout换成mouseenter和mouseleave,在IE8和最新版的grome和firefox里面一切就正常了啊,用IETester测试,连IE6都表现正常啊,IE9没有任何反应啊,就像没有加载js一样,IETester是不是坏了啊,我的IETester里的IE7一向都是打不开测试页面的,所以不知都IE7会怎么样啊,IETester很不好用啊,有木有推荐的其他工具啊?(欢迎补充更正具体的测试结果啊)

好吧,回正题,为什么会这样呢?

其实是就是因为DOM3级事件中定义的mouseenter、mouseleave都不冒泡,在光标移动到后代元素上不会触发。但DOM2级事件并没有定义这个事件,DOM3级事件将它纳入了规范,IE、Firefox9+和Opera支持这个事件。

就是这个样子啊。

但是非要用mouseover和mouseout的话, 

W3C在mouseover和mouseout这两个触发的事件对象里添加了一个叫relatedTarget的属性,来表示与事件相关的DOM元素。event.mouseover中event.relatedTarget指向鼠标来自的元素,而mouseout中的relatedTarget指向的是鼠标去向的那个元素。据说在IE里对应的分别是event.fromElement和event.toElement(没测试过啦,jQuery都统一成event.relatedTarget)。

 

吐槽:原来写稍微技术一点的博客这么费时间啊, 从上午8点写到现在14:00,上午不过是打了2、3个小电话,填了些资料,中午都木有午休啊,原计划还要写一些UI事件的(UI事件是指那些不一定与用户操作有关的事件,如load、resize、scroll等,有时间再补充啊)。

总结:写技术博客最好还是放在晚上吧。

俺要工作了啊,看见有错的地方恳请指正啊,谢恩。

posted @ 2013-08-20 14:29  荔枝龙眼  阅读(394)  评论(0编辑  收藏  举报

这里是页脚Html代码