由event.target引发的关于事件流的一连串思考(二)

阻止事件冒泡

W3C的方法是ev.stopPropagation(),IE则是使用ev.cancelBubble = true。

先不谈IE的私有方法,首先讨论一个问题:ev.stopPropagation()真的是阻止事件冒泡吗?

实际上,这个问题需要分两种情况来讨论:

  1. DOM0的阻止冒泡事件
    还是同心圆的例子,代码如下。
    JavaScript:
var div = document.querySelector("div");
var ul = document.querySelector("ul");
var li = document.querySelector("li");
div.onclick = function(ev){
    console.log("div");
}
ul.onclick = function(ev){
    console.log("ul");
}
li.onclick = function(ev){
    console.log("li");
    ev.stopPropagation();
}

此时输出结果如下:


DOM0阻止事件

可以看到阻止事件冒泡成功了,证明DOM0确实是阻止事件冒泡。

  1. DOM2的阻止冒泡事件
    还是同心圆的例子,代码如下:
var div = document.querySelector("div");
var ul = document.querySelector("ul");
var li = document.querySelector("li");
div.addEventListener('click',function(){
    console.log("div 捕获");
},true);
ul.addEventListener('click',function(ev){
    console.log("ul 捕获");
},true);
li.addEventListener('click',function(ev){
    console.log("li 捕获");
},true);
div.addEventListener('click',function(ev){
    console.log("div 冒泡");
});
ul.addEventListener('click',function(ev){
    console.log("ul 冒泡");
});
li.addEventListener('click',function(ev){
    console.log("li 冒泡");
});

此时点击内层圆,输出结果如下:


由event.target引发的关于事件流的一连串思考(二)_第1张图片
没有阻止事件冒泡的情况

我们将

ul.addEventListener('click',function(ev){
    console.log("ul 冒泡");
});

改为

ul.addEventListener('click',function(ev){
    console.log("ul 冒泡");
    ev.stopPropagation();
});

此时点击内层圆,输出结果如下:


由event.target引发的关于事件流的一连串思考(二)_第2张图片
阻止ul的事件冒泡

可以看到本来会冒泡到div上的点击事件被阻止了,此时跟DOM0的阻止事件冒泡是一致的。
但是如果我们改为阻止在ul的捕获事件上阻止事件冒泡的话,事件捕获还会进行吗?还是只会阻止冒泡?我们来测试一下,将

ul.addEventListener('click',function(ev){
    console.log("ul 捕获");
},true);

改为

ul.addEventListener('click',function(ev){
    console.log("ul 捕获");
    ev.stopPropagation();
},true);

此时的输出结果如下:


由event.target引发的关于事件流的一连串思考(二)_第3张图片
阻止ul的事件捕获

可以看到,不但冒泡的整个阶段被阻止了,而且li的事件捕获也被阻止了。

所以总结一下这两点,ev.stopPropagation()不止可以阻止事件冒泡,如果在捕获阶段使用还可以阻止事件捕获。

那么我们再考虑一种特殊情况:如果ev.stopPropagation()在target阶段执行会是什么情况,代码如下。
JavaScript:

div.addEventListener('click',function(){
    console.log("div 捕获");
},true);
ul.addEventListener('click',function(ev){
    console.log("ul 捕获");
},true);
li.addEventListener('click',function(ev){
    console.log("li 捕获");
    ev.stopPropagation();
},true);
div.addEventListener('click',function(ev){
    console.log("div 冒泡");
});
ul.addEventListener('click',function(ev){
    console.log("ul 冒泡");
});
li.addEventListener('click',function(ev){
    console.log("li 冒泡");
});

我们在target上阻止了事件监听,这样整个事件冒泡应该是被阻止的,我们看输出结果:


由event.target引发的关于事件流的一连串思考(二)_第4张图片
在target上阻止了事件监听

target的冒泡仍然执行了,其实原因很简单,我们在上一章已经提到了,就不多做赘述了。

阻止事件冒泡的兼容写法:

if(event.stopPropagation){
    event.stopPropagation();
}else{
    event.cancelBubble = true;
}
阻止默认事件

这个没什么好讲的,用于阻止浏览器默认的事件,比如提交按钮的点击默认提交,a标签的点击跳转等。不过之前遇到过一个问题,在jsp里无法阻止提交按钮的提交事件,最后还是换成了div然后使用form.submit()提交才通过。
兼容写法如下:

if(event.preventDefault){
    // W3C的阻止默认事件
    event.preventDefault();
}else{
    // IE私有的阻止默认事件
    event.returnValue = false;
}
事件流的常见应用:事件委托

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

阻止事件冒泡应用

有一个很应景的例子,页面有一个弹出框,可拖拽,弹出框内有一个input框,这个框内输入的文字要可以选中。
我们先来实现页面结构和拖拽功能,代码如下:




    
    Document
    


    

此时页面如下:


由event.target引发的关于事件流的一连串思考(二)_第5张图片
可拖拽页面

拖拽功能实现了,但是我们发现想要复制文本的时候,没有复制到,反而也触发了拖拽功能,这就很尴尬了。

这时我们的阻止事件冒泡就起作用了,我们在input框上阻止mousedown事件冒泡到外层,代码如下:
JavaScript:

input.onmousedown = function(ev){
    ev.stopPropagation();
}

大功告成,此时既可以复制文本,外层又可以拖拽。

参考资料:
http://www.cnblogs.com/liugang-vip/p/5616484.html
http://www.cnblogs.com/libin-1/p/6368323.html

你可能感兴趣的:(由event.target引发的关于事件流的一连串思考(二))