(1)相关概念
事件流的概念:事件流所描述的就是从页面中接受事件的顺序。
事件流也有两种,分别是事件冒泡和事件捕获,现行的主流是事件冒泡。
以上就是通过原生js将每一个div都绑定了一个事件,且通过useCapture这个参数将事件类型设置为true(捕获)或者
false(默认为false,冒泡)
需要注意的是:更改事件流的属性,只能通过原生js中的方法,因为只有原生js中有更改事件流属性的参数,其它没有。jquery的事件流是冒泡型的,里面的事件都是冒泡型的,没法更改事件流的属性,因为方法中没有更改事件流的参数。
冒泡事件定义:
在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。
事件委托机制:
由冒泡事件衍生出的事件委托机制,既然事件是冒泡传递的,那可以让某个父节点统一处理事件,通过判断事件的发生地(即事件产生的节点),然后做出相应的处理。就是将子元素的事件处理程序绑定到父类上,例如常见的ul>li> a列表标签的写法应用。
此处给出一个委托机制的例子:
源程序:
<ul>
<li id="ll">选项一</li>
<li>选项二</li>
<li>选项三</li>
<li>选项四</li>
</ul>
第一种写法:直接利用子元素的选择,没有绑定父元素,没有实现委托机制
$("li").mouseover(function () {
console.log(event.target);
$(this).css("background-olor","#ffff00").siblings().css("background-color","#1d7b15");
});
效果:
第二种写法:委托父类,实现委托机制,但是内容判断上通过原生js实现
$("ul").on("mouseover", function () {
console.log(event.target);
var lis = document.getElementsByTagName("li");
for (var i = 0; i < lis.length; i++) {
if (event.target && event.target == lis[i]) {
$(event.target).css("background-color", "#ffff00").siblings().css("background-color", "#1d7b15");
}
}
});
效果:
第三种写法:委托父类,实现委托机制,但是通过过滤器筛选出要作用的子元素li,这种方法最简单。
$("ul").on("mouseover","li", function (event) {
$(event.target).css("background-color", "#ffff00").siblings().css("background-color", "#1d7b15");
});
$(selector).on(event,childSelector,data,function,map)
childSelector 可选。规定只能添加到指定的子元素上的事件处理程序,且不是选择器本身,即就是 对父元素触发事件的一种过滤。
效果:
小结:三种方法都可以,建议第三种方法,简单方便。
捕获机制:
事件捕获指的是从document到触发事件的那个节点,即自上而下的去触发事件。而事件冒泡是自下而上的去触发事件。绑定事件方法的第三个参数,就是控制事件触发顺序是否为事件捕获,true是事件捕获,false是事件冒泡。默认false,即事件冒泡。通常可以用Jquery的e.stopPropagation会阻止冒泡,意思就是到我为止,我的爹和祖宗的事件就不要触发了。
(2)jQuery 提供了两种方式来阻止事件冒泡。
方式一:event.stopPropagation();
$("#div1").mousedown(function(event){
event.stopPropagation();
});
方式二:return false;
$("#div1").mousedown(function(event){
return false;
});
但是这两种方式是有区别的。return false 不仅阻止了事件往上冒泡,而且阻止了事件本身。event.stopPropagation() 则只阻止事件往上冒泡,不阻止事件本身。
(3)阻止捕获的方法
stopPropagation()方法既可以阻止事件冒泡,也可以阻止事件捕获,也可以阻止处于目标阶段。
无论事件流中只有捕获还是事件流中只有冒泡,还是说是事件流中既有捕获还有冒泡,event.stopPropagation()都可以阻止事件流的传播顺序。只要是event.stopPropagation()加在哪里,则到哪里就停止运行,停止捕获或者停止冒泡,简单说是,仍然按照正常的混合机制流程走,只是哪里有e.stopPropagation()则这个流程到哪里就停止了。
(4)捕获与冒泡相关例子
源程序:
<div id="div1" class="parent">div1
<div id="div2" class="child">div2
<div id="div3">div3
<div id="div4">div4</div>
</div>
</div>
</div>
(A)只测试捕获情况
<script>
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
var div3 = document.getElementById("div3");
var div4 = document.getElementById("div4");
div1.addEventListener("click", function (e) {
alert("div1::" + e.target);
}, true);
div2.addEventListener("click", function (e) {
alert("div2::" + e.target);
}, true);
div3.addEventListener("click", function (e) {
alert("div3::" + e.target);
}, true);
div4.addEventListener("click", function (e) {
alert("div4::" + e.target);
}, true);
</script>
以上的代码中,若是点击最里面的div4区域,则弹窗出现的顺序为:div1--》div2--》div3--》div4,
即使符合捕获条件的。就是先出现最外层捕获,最后才是自己。
(B)事件流中既含有捕获事件有含有冒泡事件的混合情况
<script>
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
var div3 = document.getElementById("div3");
var div4 = document.getElementById("div4");
div1.addEventListener("click", function (e) {
alert("div1::" + e.target);
}, true);
div2.addEventListener("click", function (e) {
alert("div2::" + e.target);
}, false);
div3.addEventListener("click", function (e) {
alert("div3::" + e.target);
}, true);
div4.addEventListener("click", function (e) {
alert("div4::" + e.target);
}, false);
<script>
这里是事件流中既有冒泡也有捕获
W3C明智地在这场争斗中选择了一个折中的方案:任何发生在w3c事件模型中的事件,首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段。
以上的脚本代码中:div1和div3是捕获事件流,div2和div4是冒泡事件流。
若是点击div4,则结果是:div1--》div3-》div4--》div2
很明显就是先捕获,然后冒泡。
若是点击div3,则结果为:div1--》div3--》div2
(C)混合情况下阻止捕获情况
<script>
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
var div3 = document.getElementById("div3");
var div4 = document.getElementById("div4");
div1.addEventListener("click", function (e) {
alert("div1::" + e.target);
}, true);
div2.addEventListener("click", function (e) {
alert("div2::" + e.target);
}, false);
div3.addEventListener("click", function (e) {
alert("div3::" + e.target);
e.stopPropagation(); }, true);
div4.addEventListener("click", function (e) {
alert("div4::" + e.target);
}, false);
这依旧是一种捕获和冒泡共存的情况,若是点击div4,则结果div1---》div3,因为到div3就停止捕获了。
(D)混合情况下阻止冒泡情况
<script>
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
var div3 = document.getElementById("div3");
var div4 = document.getElementById("div4");
div1.addEventListener("click", function (e) {
alert("div1::" + e.target);
}, true);
div2.addEventListener("click", function (e) {
alert("div2::" + e.target);
}, false);
div3.addEventListener("click", function (e) {
alert("div3::" + e.target);
}, true);
div4.addEventListener("click", function (e) {
alert("div4::" + e.target);
e.stopPropagation();
}, false);
此时若是点击div4,则结果为div1—》div3—》div4,因为到div4就已经停止冒泡了。
小结:
冒泡是从目标元素往父元素走,捕获是从祖宗元素开始往目标元素走;两个都有的话先捕获再冒泡。