CSS 中 stopPropagation, preventDefault 和 return false 的區別

龐順龍發表於2019-05-11

監聽事件, 在在節點上能被監聽的頁面操作. 如: select 節點的 change 事件, a 節點的 click 事件.
瀏覽器預設動作, 指特定頁面元素上帶有的功能. 如: 點選 a 連結節點的跳轉動作, 表單提交動作.

因為事件可以在各層級的節點中傳遞, 不管是冒泡還是捕獲, 有時我們希望事件在特定節點執行完之後不再傳遞, 可以使用事件物件的stopPropagation()方法.

假設頁面上存在一個浮動彈出層, 顯示在最前面, 當點選彈出層以外頁面區域時, 隱藏彈出層. 為了做到這樣的效果, 我們會監聽documentElement的 click 事件, 一旦事件被觸發即隱藏彈出層. 但是...

這顯然存在問題. 當使用者點選彈出層時, 我們不希望它隱藏掉. 但因為事件的冒泡傳遞,documentElement的 click 事件也會被觸發. 這個時候, 我們可以監聽彈出層的 click 事件, 並使用stopPropagation()方法阻止冒泡. 請參考下面的程式碼.

// 在彈出對話方塊上點選時, 不進行任何頁面操作, 並阻止冒泡document.getElementById('dialog').onclick = function(ev) { ev.stopPropagation();}; // 在 documentElement 節點上監聽到點選事件時, 隱藏對話方塊document.documentElement.onclick = function(ev) { document.getElementById('dialog').style.display = 'none';};

stopPropagation()相當好用, 可是 IE8 及以前版本都不支援. IE 的事件物件包含特有的屬性cancelBubble, 只要將它賦值為 false 即可阻止事件繼續. 如:

// 在彈出對話方塊上點選時, 不進行任何頁面操作, 並阻止冒泡document.getElementById('dialog').onclick = function(ev) { ev.cancelBubble = false;};

一個帶事件監聽的連結程式碼如下:

<a href="http://w3c.org" onclick="alert('JavaScript Click Event');">點選連結</a>

點選該連結, 顯示對話方塊後跳轉頁面. 由此可知, 除了執行監聽事件還會觸發瀏覽器預設動作; 執行監聽事件在前, 觸發瀏覽器預設動作在後.

這裡有個經典示例, 我們希望點選連結在新視窗開啟頁面, 但不希望當前頁面跳轉. 這個時候可以使用preventDefault()阻止後面將要執行的瀏覽器預設動作.

<a id="link" href="http://w3c.org">W3C 首頁連結</a> <script>// 在新視窗, 開啟頁面document.getElementById('link').onclick = function(ev) { // 阻止瀏覽器預設動作 (頁面跳轉) ev.preventDefault(); // 在新視窗開啟頁面 window.open(this.href);};</script>

退出執行,return false之後的所有觸發事件和動作都不會被執行. 有時候return false可以用來替代stopPropagation()和preventDefault(), 比如我們上面新視窗開啟連結的例子, 如:

<a id="link" href="http://w3c.org">W3C 首頁連結</a> <script>// 在新視窗, 開啟頁面document.getElementById('link').onclick = function(ev) { // 在新視窗開啟頁面 window.open(this.href); // 退出執行 (在監聽事件之後執行的瀏覽器預設動作將不會被執行) return false;};</script>

有人認為return false=stopPropagation()+preventDefault(), 其實是錯的.return false不但阻止事件, 還可以返回物件, 跳出迴圈等... 方便地一刀切而不夠靈活, 濫用易出錯.

內容均為作者獨立觀點,不代表八零IT人立場,如涉及侵權,請及時告知。

相關文章