咱們以一個文件上傳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; });