咱们以一个文件上传ui重设计为例子来探讨这几个函数的区别:css
其中的html代码以下:html
<div class="file-upload"> <input type="file" name="upload-file" class="file-upload__input" style="display: none;" /> <div class="file-upload__drop-zone"> <span class="file-upload__drop-zone-text">Drop files here</span> <a href="#" class="file-upload__btn--upload">Upload files</a> </div> </div>
HTML包含有三部份内容:jquery
1. 一个inpyout空间来处理文件上传的对话.在这里,咱们设置为hidden,由于咱们并不想使用浏览器默认给出的控件;浏览器
2. 一个class为file-upload__dropzone的div元素,它做为主要的"drop zone"拖拽区,若是有代码支持的话,能够直接拖拽文件到这个区域。app
3. 一个a元素,它具备file-upload__btn--upload做为其css类,它做为实际的"upload files"按钮,当咱们点击它时,就可以打开文件选择对话框函数
Javascript部分:ui
function fileUpload() { document.querySelector('.file-upload__input').click(); } const dropzone = document.querySelector('.file-upload__drop-zone'); const button = document.querySelector('.file-upload__btn--upload'); dropzone.addEventListener('click', fileUpload); button.addEventListener('click', fileUpload);
js也有三部分组成:this
1. 一个fileUpload函数用于触发input元素的click事件url
2.div和a元素获取并赋予变量spa
3.给这几个元素添加事件侦听,当click时就调用fileUpload函数以模拟触发file input的点击
若是咱们直接实验,咱们会发现不少诡异的行为:当第一个对话框打开并选择文件后,又有第二个会打开
该函数用于阻止浏览器的默认行为(好比当咱们点击a标签的时候,天然就打开a中的连接,这个行为就是默认的行为),可是并不会阻止事件的bubbling,也就是说其父亲元素依然会接受到对应该元素的事件
在咱们的例子中,当咱们点击upload files按钮时,就会调用fileUpload函数,这和咱们的预期时一致的。
而做为a标签,其默认行为是引导浏览器nav到href所指定的url中,在这里,咱们设置为#,大多数浏览器解释为跳到页面的top处。
而跳转到页面的top处可能并非咱们但愿的行为,所以,咱们能够经过使用preventDefault方法来阻止这个行为。
经过修改咱们的js代码,咱们能够阻止a标签的默认行为,可是依然会调用fileUpload函数:
dropzone.addEventListener('click', fileUpload); button.addEventListener('click', (event) => { event.preventDefault(); fileUpload(); });
这时,虽然点击a标签再也不跳转到页面top处,可是文件对话框依然会弹出两次。。。
须要注意的是:
1.preventDefault有继承性,若是在父亲元素的事件处理函数中调用了event.preventDefault,那么子元素对应的event默认行为也将丢失
2.若是但愿在子组件中要覆盖这个行为,咱们能够经过在子组件的event handler中最后执行 return true; 来恢复!
有的时候,浏览器的行为很是奇怪,每每就是由于在某些组件上调用过preventDefault函数,而咱们又没法知晓是哪一个元素身上调用的,这时须要调试。
一个比较好的聪敏的办法是使用相似proxy代理wrapper将event的该函数从新包装:
var oldEPD = Event.prototype.preventDefault; Event.prototype.preventDefault = function() { debugger; oldEPD.call(this); };
这样的话就会在有该调用时代码中止供咱们查找
这个函数能够阻止发生在子元素上的事件继续向上冒泡,可是不会阻止浏览器的默认行为.
上面的例子中,因为咱们点击a元素后,a元素的click handler中会触发对话框,而随后a的click事件继续bubble到上级元素,也就是dropzone,而该dropzone元素也有监听click事件所以就又会被调用fileUpload,这就是为何文件对话框弹出两次的缘由。咱们能够经过stopPropagation来阻止事件继续网上冒泡。
咱们来看终级解决方案:
dropzone.addEventListener('click', fileUpload); button.addEventListener('click', (event) => { event.preventDefault(); event.stopPropagation(); fileUpload(); });
一般return false这个代码仅仅在jQuery的事件处理函数中有效,对于原生的js代码并没有任何影响。
而在jquery的代码中return false又有两个效果:
1. preventDefault
2. stopPropagation
const dropzone = $('.file-upload__drop-zone'); const button = $('.file-upload__btn--upload'); $(dropzone).on('click', fileUpload); $(button).on('click', (event) => { fileUpload(); return false; });