抽空学习了下javascript和jquery的事件设计,收获颇大,总结此贴,和大家分享。
(一)事件绑定的几种方式
javascript给DOM绑定事件处理函数总的来说有2种方式:在html文档中绑定、在js代码中绑定。下面的方式1、方式2属于在html中绑定事件,方式3、方式4和方式5属于在js代码中绑定事件,其中方法5是最推荐的做法。
HTML的DOM元素支持onclick、onblur等以on开头属性,我们可以直接在这些属性值中编写javascript代码。当点击div的时候,下面的代码会弹出div的ID:
这种做法很显然不好,因为代码都是放在字符串里的,不能格式化和排版,当代码很多的时候很难看懂。这里有一点值得说明:onclick属性中的this代表的是当前被点击的DOM对象,所以我们可以通过this.id获取DOM元素的id属性值。
当代码比较多的时候,我们可以在onclick等属性中指定函数名。 function buttonHandler(thisDom) 跟上面的做法相比,这种做法略好一些。值得一提的是:事件处理函数中的this代表的是window对象,所以我们在onclick属性值中,通过this将dom对象作为参数传递。 代码中通过dom元素的onclick等属性 这种做法this代表当前的DOM对象。还有一点:这种做法只能绑定一个事件处理函数,后面的会覆盖前面的。 函数进行事件绑定和取消。 attachEvent/detachEvent兼容性不好,IE6~IE11都支持该函数,但是FF和Chrome浏览器都不支持该方法。而且attachEvent/detachEvent不是W3C标准的做法,所以不推荐使用。在IE浏览器下,attachEvent有以下特点。 a) 事件处理函数中this代表的是window对象,不是dom对象。 b) 同一个事件处理函数只能绑定一次。
虽然使用attachEvent绑定了2次,但是函数a只会调用一次。 c)不同的函数对象,可以重复绑定,不会覆盖。
匿名函数和匿名函数是互相不相同的,即使代码完全一样。所以如果我们想用detachEvent取消attachEvent绑定的事件处理函数,那么绑定事件的时候不能使用匿名函数,必须要将事件处事函数单独写成一个函数,否则无法取消。
这2个函数是W3C标准规定的,FF和Chrome浏览器都支持,IE6/IE7/IE8都不支持这2个函数。不过从IE9开始就支持了这2个标准的API。
a) 事件处理函数中this代表的是dom对象,不是window,这个特性与attachEvent不同。
b) 同一个事件处理函数可以绑定2次,一次用于事件捕获,一次用于事件冒泡。
如果绑定的是同一个事件处理函数,并且都是事件冒泡类型或者事件捕获类型,那么只能绑定一次。
c) 不同的事件处理函数可以重复绑定,这个特性与attachEvent一致。 方式1、方式2和方式3都不能实现事件的重复绑定,所以自然也就不存在执行顺序的问题。方式4和方式5可以重复绑定特性,所以需要了解下执行顺序的问题。如果你写出依赖于执行顺序的代码,可以断定你的设计存在问题。所以下面的顺序问题,仅作为兴趣探讨,没有什么实际意义。直接上结论:函数,先绑定的先执行。下面的代码我在IE11、FF17和Chrome39都测试过。
当点击outA的时候,会依次打印出1、2、3、4。这里特别需要注意:我们给outA绑定了多个onclick事件处理函数,也是直接点击outA触发的事件,所以不涉及事件冒泡和事件捕获的问题,即addEventListener的第三个参数在这种场景下,没有什么用处。如果是通过事件冒泡或者是事件捕获触发outA的click事件,那么函数的执行顺序会有变化。 事件冒泡和事件捕获很好理解,只不过是对同一件事情的不同看法,只不过这2种看法都很有道理。
我们知道HTML中的元素是可以嵌套的,形成类似于树的层次关系。比如下面的代码:
如果点击了最内侧的outC,那么外侧的outB和outC算不算被点击了呢?很显然算,不然就没有必要区分事件冒泡和事件捕获了,这一点各个浏览器厂家也没有什么疑义。假如outA、outB、outC都注册了click类型事件处理函数,当点击outC的时候,触发顺序是A-->B-->C,还是C-->B-->A呢?如果浏览器采用的是事件冒泡,那么触发顺序是C-->B-->A,由内而外,像气泡一样,从水底浮向水面;如果采用的是事件捕获,那么触发顺序是A-->B-->C,从上到下,像石头一样,从水面落入水底。
事件冒泡见下图: 事件捕获见下图:
{
alert(this.id);//undefined
alert(thisDom.id);//outestA
return false;
}
{
alert(this.id);//undefined
}
{
alert(this.id);//outestA
}
(二)事件处理函数的执行顺序
(三) 事件冒泡和事件捕获
一般来说事件冒泡机制,用的更多一些,所以在IE8以及之前,IE只支持事件冒泡。IE9+/FF/Chrome这2种模型都支持,可以通过addEventListener((type,useCapture)的useCapture来设定,useCapture=false代表着事件冒泡,useCapture=true代表着采用事件捕获。
window.onload = function(){
var outA = document.getElementById("outA");
var outB = document.getElementById("outB");
var outC = document.getElementById("outC");
// 使用事件冒泡
outA.addEventListener('click',false);
outB.addEventListener('click',false);
outC.addEventListener('click',false);
};