来源: 我的博客
想必好多童鞋都有直接复制粘贴event.preventDefault() 或者event.stopPropagation() 的经历,可是为何这样作不甚了解,今天咱们的目的就是要完全搞懂这一区别。javascript
为了完全弄清楚它们之间的区别,我不得不要先说一下javascript中两种事件传播模式:html
- 捕获模式(capturing) - 冒泡模式(bubbling)
捕获模式又称为“滴流模式”(trickling),我的认为滴流模式更好理解,滴流就是“从上向下”,而冒泡就是“从下向上”,好了,先记住这两种模式的特色。java
同时你还要记住,这两种模式是为了干什么的?
这两种模式就是为了一点:决定html中“元素”(好比div, p, button)接收到事件的“顺序”!固然接收到事件的顺序不一样,天然事件监听函数被触发的顺序就不一样了,因而间接地就出现了监听函数被执行顺序的不一样。git
因此。。github
当事件发生时,该事件首先被最外层元素接受到,而后依次向内层元素传播。(从上向下)浏览器
当事件发生时,该事件首先被最内层元素接受到,而后依次向外层元素传播。(从下向上)函数
顺便提一句,之前网景公司主推捕获模式而微软则偏向于冒泡模式,不过二者都是W3C DOM事件标准(2000)。spa
IE9如下仅仅支持冒泡模式,可是IE9+以及如今的主流浏览器都支持两种模式了。code
用哪一种事件传播方式彻底是咱们本身说了算的,咱们可使用htm
addEventListener(type, listener, useCapture)
来注册事件处理方式,以及以何种传播模式进行。
<div id="outerMost"> <div id="middle"> <a href="" id="innerMost" >click</a> </div> </div>
咱们能够对上述代码添加一些样式,这样在网页中更直观。
<div id="outerMost" style="border: 1px solid black; width: 150px; height: 120px; padding: 20px;"> outerMost <div id="middle" style="border: 1px solid black; width: 60px; height: 60px; padding: 20px;"> Middle <a href="" id="innerMost" style="border: 1px solid black; width: 30px; height: 20px; display: block; margin: 20px;">click</a> </div> </div>
如图:
对最外层,中间层,最内层分别用“捕获”模式注册事件监听,咱们上面说了,若是使用捕获模式,那么addEventListener第三个参数应该是true,不然则是冒泡模式,若是不声明,默认为冒泡模式。
var outerElement = document.getElementById('outerMost'); var middleElement = document.getElementById('middle'); var innerElement = document.getElementById('innerMost'); outerElement.addEventListener('click', function () { console.log('trigger outermost div'); }, true); middleElement.addEventListener('click', function () { console.log('trigger middle div'); }, true); innerElement.addEventListener('click', function () { console.log('trigger innermost button'); }, true);
咱们点击中间层Middle字样,如图:
能够看到,事件触发从外向里进行,若是你们把addEventListener中第三个参数改成false或者留空,点击middle字样,则会获得相反的结果,你们能够本身试一下。
终于到了谈一谈preventDefault 和 stopPropagation了,你们可能注意到了,我上面的例子中没有涉及到点击click连接,为何呢?你们能够试一下,点击click会发生什么?它会又当即跳转到了当前页面(由于咱们href是一个空链接,这是连接元素的一个默认特性),虽然咱们的监听函数被执行了,可是有时候咱们不想这个默认特性被执行,好比,咱们可能想在监听函数里面改变div的背景颜色等等,这样若是这个连接元素a默认特性的存在就会当即“刷新”了该页面,让咱们的改变背景颜色没法进行。
因此为了“阻止”元素的“默认特性”,因此事件对象中有了一个preventDefault方法,以下:
innerElement.addEventListener('click', function (event) { event.preventDefault(); console.log('trigger innermost button'); }, true);
这样咱们点击click就会获得:
trigger outermost div trigger middle div trigger innermost button
那么stopPropagation呢?
向上面这种状况,若是当你点击click的时候,只想出发绑定在click上的监听函数,而不想触发“传播链”上的其余函数,那么则使用stopPropagation。
注意:你在那个事件监听函数中使用event.stopPropagation();那么传播链就会终止,向上面这个例子,由于咱们使用的是捕获模式,即便咱们添加了:
innerElement.addEventListener('click', function (event) { event.preventDefault(); event.stopPropagation(); console.log('trigger innermost button'); }, true);
依然会获得和上面同样的结果,为何呢?由于捕获模式是由外往里传播,咱们只是在a这里阻止了继续像里传播,由于没有更里的元素了,因此结果同样,为了更好地演示,咱们能够把捕获模式改成冒泡模式以下:
var outerElement = document.getElementById('outerMost'); var middleElement = document.getElementById('middle'); var innerElement = document.getElementById('innerMost'); outerElement.addEventListener('click', function (event) { console.log('trigger outermost div'); }); middleElement.addEventListener('click', function () { console.log('trigger middle div'); }); innerElement.addEventListener('click', function (event) { event.preventDefault(); event.stopPropagation(); console.log('trigger innermost button'); });
这样点击click,就只获得了一条log:
trigger innermost button
最后说一下return false; 这是jQuery中提供,好比:
$('#innermost').on('click', function () { return false; })
它帮咱们同时作了:
- event.preventDefault(); - event.stopPropagation();
这两个工做,你能够看作是一种快捷方式,可是你在原生javascript中的监听回调函数中写return false; 是没有任何用的。好比:
innerElement.addEventListener('click', function (event) { return false; });
只是jQuery提供的一种特性。