2020年9月18日 星期五

Javascript 函數傳回 return false 的問題

在 Javascrip/jQuery 的事件處理函數中常看到最後用 return false 結尾的用法, 常令人疑惑其用意是甚麼, 其實這是不要讓 HTML 元素執行其預設動作的方法, 例如超連結 a 元素的預設動作是將網頁導向 href 所指之位置; 而 form 元素的預設動作是提交表單 :
  • href="#" : 表示導向該網頁中的一個錨點 (anchor)
  • href="hello.htm" : 表示導向此網站的另一個網頁 hello.htm
  • href="http://www.foo.com/bar.htm" : 表示導向另一個網站之網頁
如果在 a 元素的 click 事件處理函數中最後傳回 false, 則 a 元素預設的連結導向動作會被取消, 例如下面範例中的兩個 a 元素都連結到本網頁之錨點 "#" :

  <a href="#" id="a1">a1</a>
  <a href="#" id="a2">a2</a>

其中的 id=a2 的超連結有特別掛上 click 事件處理器, 並且傳回 false, 而 id=a1 則沒有 : 

$("#a2").on("click", function(){
  return false;
  });

按 a1 超連結後網址列最後會多出一個 "#" 表示網頁會回到網頁的最上方, 但按 a2 超連結則不會, 參考 :


測試 1 : 超連結導向本網頁錨點 href="#" [看原始碼]

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>jQuery test</title>
  <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
</head>
<body>
  <a href="#" id="a1">a1</a>
  <a href="#" id="a2">a2</a>
  <script>
    $(function(){
      $("#a2").on("click", function(){
        return false;
        });
      });    
  </script>
</body>
</html>

傳回 false 常見於將 a 元素當作按鈕用時, 當按下按鈕會執行事件處理函數, 如果不禁止其執行預設之網頁重導向動作, 事件處理函數執行完後網頁會回到網頁最上方 (href="#" 的預設動作), 造成網頁移動的不好觀感, 例如 : 


測試 2 : 超連結當作按鈕時使用 return false 停止預設動作 [看原始碼]

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>jQuery test</title>
  <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
  <link href="https://code.jquery.com/ui/1.12.1/themes/hot-sneaks/jquery-ui.css" rel="stylesheet">
  <style>
    body {font-family: Arial, Helvetica, sans-serif;}
    .ui-widget {font-size:80%;}
  </style>
</head>
<body>
  <div style="height: 1000px;"></div>
  <a href="#" id="a1">a1</a>
  <a href="#" id="a2">a2</a>
  <script>
    $(function(){
      $("#a1").button();
      $("#a2").button();
      $("#a1").on("click", function(){
        alert("你按了 a1");
        });
      $("#a2").on("click", function(){
        alert("你按了 a2");
        return false;
        });
      });    
  </script>
</body>
</html>

此例中使用一個高度為 1000px 的 div 元素將按鈕推到網頁底下, 可見按 a1 按鈕後因為沒有垂回 false 導致執行 href="#" 的預設動作 (回到網頁最上方), 但按 a2 按鈕則網頁不會移動

但是在 "jQuery 應用程式設計極速上手" (Jay Blanchard, 上奇) 這本書裡的第 1-15 頁提到, 使用 return false 來停止預設動作可能會有問題, 因為 return false 實際上會先後呼叫事件物件 e 的e.preventDefault() 與 e.stopPropogation() 函數, 前者會停止預設動作, 後者會停止事件上升 (bubble up) 功能, 因此會把之後加入之超連結的 click 事件給阻擋掉, 使得預期的功能沒有出現.

比較妥當的做法應該是呼叫 preventDefault() 即可而不是 return false :

$("#a2").on("click", function(e){
   e.preventDefault();
  });

參考下面這篇文章, 作者清楚描述了 return false 的作用, 如果只是要停掉預設動作, 那就呼叫事件物件 e 的 preventDefault() 就好, 不要使用 return false : 


沒有留言:

張貼留言