2013年3月20日 星期三

測試 jQuery 的 Ajax 方法 load()

這幾天重拾 jQuery 書本, 複習了 Ajax 的用法, 發覺以前寫自己的個人專案都囫圇吞棗, 只要能用, 會 work 就行, 沒有仔仔細細去玩味一項技術, 其實學再多也沒入味. 交互重看幾本手邊的書,  把 jQuery 的 Ajax 方法中的 load 仔細測試了一番, 印證書中的描述, 我覺得要用 Ajax 只要會使 jQuery 的 load() 方法就行啦, 摘要整理如下.

load() 的語法 :

load(url [, data] [, callback])

load() 是 jQuery 從伺服器非同步擷取資料的最簡單方法, 它跟 get() 與 post() 同樣屬於第二層次的 Ajax 方法 (ajax 函式是第一層, 而 getJSON 與 getScript 是第三層), 但不同的是, load() 乃是包裹集合 (jQuery 物件) 的方法; 而 get() 與 post() 是公用函式 (utility), 屬於 jQuery 的頂層函式.當偵測到成功回應時, load() 會將傳回的資料設定為相符元素的 HTML 內容. 例如 :

$('#result').load("ajaxtest/test.htm");

//從伺服器取回 test.htm 插入到 id=result 元素的 HTML 內容中.

必要引數 url 字串不限於 htm/html 檔, 可以是 asp/jsp/php/aspx 等任何伺服端程式. 若 url 引數為伺服端程式, 可以在後面附帶 http 參數, 例如 :

$('#result').load("test.php?user=tony&pwd=123");

可選引數 data 是發送到伺服器的請求參數, 而 load() 方法的傳遞方式基本上是根據有無 data 引數與其型態來自動決定的. 沒有傳入 data 引數時預設是用 GET 方式傳送, 而有傳入 data 時, 若 data 是以 {key:value} 物件實體表示, 則以 POST 方式傳送, 若是以請求字串表示, 則是用 GET 方式傳送 (在 PHP 中, url 所帶參數要用 $_GET[] 取得, 而物件實體的 data 所帶參數要用 $_POST[] 取得). 例如 :

$("#result").load("test.php?user=tony&pwd=123"); //GET
$("#result").load("test.php",{user:"tony",pwd:"123"); //POST
$("#result").load("test.php","user=tony&pwd=123"); //GET
$("#result").load("test.php?user=tony",{pwd:"123"); //POST

可選參數 callback 是當請求完成 (complete) 時觸發之回呼函式 (不論 Ajax 請求是否成功), 如果有指定回呼的話, 會在 HTML 插入 DOM 後才會執行回呼函式. 回呼函式有 3 個可選參數 : responseText, textStatus, 與 XMLHttpRequest. 例如 :

$("#result").load("http://mybidrobot.allalla.com/ajaxtest/test.php",
  function(responseText,textStatus,XMLHttpRequest) {
  var msg="載入完成!\n" +
                 "responseText=" + responseText + "\n" +
                 "textStatus=" + textStatus + "\n" +
                 "XMLHttpRequest=" + XMLHttpRequest + "\n";
  alert(msg);
  });

跟 $.get() 與 $.post() 不同的是, load() 允許對擷取結果進行過濾, 這是透過在 url 參數後面添加 jQuery 選擇器來達成的. 若 url 字串中包含空格, 則第一個空格後面的字串會被視為 jQuery 選擇器. 例如 :

$('#result').load("test.htm .myClass");

此例是取得 test.htm 後進行過濾, 取出所有 class=myClass 元素的內部內容, 插入到 id=result 元素的 HTML 內容中.

$('#result').load("test.htm #myID"); 

此例是取得 test.htm 後進行過濾, 取出 id=myID 元素的內部內容, 插入到 id=result 元素的 HTML 內容中.

以下實際測試範例以兩個遠端檔案 test.htm 與 test.php 為載入對象, test.htm 內容如下 :

<p style='font-weight:bold;'>Hello World!</p>
<p id='normal'>Hello World!</p>

test.php 內容如下 :

<?php
echo "<p>get :user=".$_GET['user'].", pwd=".$_GET['pwd']."</p>".
     "<p>post : user=".$_POST['user'].", pwd=".$_POST['pwd']."</p>".
     "<p style='font-weight:bold;'>Hello World!</p>".
     "<p id='normal'>Hello World!</p>";
?>



<!DOCTYPE html>
<html>
<head>
  <title>Ajax load test</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
  <div id="result"></div>
  <input type="button" id="load" value="load">
  <script>   
    $(function(){
      $("#load").click(function() {
        $("#result").load("test.htm");
        });
      });
  </script>
</body>
</html>

此例只是單純載入一個 htm 檔.


範例 2 : 載入 test.php 並過濾結果 (只提取 id=normal 之元素) [看原始碼]

<!DOCTYPE html>
<html>
<head>
  <title>Ajax load test</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
  <div id="result"></div>
  <input type="button" id="load" value="load">
  <script>   
    $(function(){
      $("#load").click(function() {
        $("#result").load("http://tony1966.xyz/test/ajaxtest/test.php #normal");
        });
      });
  </script>
</body>
</html>

此例是載入一個 php 檔, 並驗證 url 字串中的 jQuery 選擇器. 伺服器回傳內容中有兩個 p 元素, 利用 "test.php #normal" 過濾出第二個 p, 因為其 id 為 normal.


範例 3 : 載入 php 檔並在 url 中帶參數 ( GET) [看原始碼]

<!DOCTYPE html>
<html>
<head>
  <title>Ajax load test</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
  <div id="result"></div>
  <input type="button" id="load" value="load">
  <script>   
    $(function(){
      $("#load").click(function() {
        $("#result").load("test.php?user=tony&pwd=123");
        });
      });
  </script>
</body>
</html>

此例主要是不傳入 data 引數, 但在 url 字串中傳送要求字串 "test.php?user=tony&pwd=123", 在伺服端用 $_POST[] 將讀取不到參數, 要用 $_GET[] 才行, 證實用 url 字串傳送要求字串時, Ajax 引擎是以 GET 方式傳送.



<!DOCTYPE html>
<html>
<head>
  <title>Ajax load test</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
  <div id="result"></div>
  <input type="button" id="load" value="load">
  <script>   
    $(function(){
      $("#load").click(function() {
        $("#result").load("test.php",{user:"tony",pwd:"123"});
        });
      });
  </script>
</body>
</html>

此例主要是以物件實體 {user:"tony",pwd:"123"} 傳送要求參數, 在伺服端用 $_GET[] 將讀取不到參數, 要用 $_POST[] 才行, 證實 data 是物件實體時, Ajax 引擎是以 POST 方式傳送.



<!DOCTYPE html>
<html>
<head>
  <title>Ajax load test</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
  <div id="result"></div>
  <input type="button" id="load" value="load">
  <script>   
    $(function(){
      $("#load").click(function() {
        $("#result").load("test.php","user=tony&pwd=123");
        });
      });
  </script>
</body>
</html>

此例主要是傳入 data 引數, 但不是以物件實體 {} 表示, 而是以要求字串 "user=tony&pwd=123" 表示, 在伺服端用 $_POST[] 將讀取不到參數, 要用 $_GET[] 才行, 證實即使傳入 data 引數, 也必須是用物件實體, Ajax 引擎才會以 POST 方式傳送, 若用字串表示, 則會用 GET 方式.



<!DOCTYPE html>
<html>
<head>
  <title>Ajax load test</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
  <div id="result"></div>
  <input type="button" id="load" value="load">
  <script>   
    $(function(){
      $("#load").click(function() {
        $("#result").load("test.php?user=tony",{pwd:"123"});
        });
      });
  </script>
</body>
</html>

此例主要是將兩個要求參數分別以 url 字串 "test.php?user=tony" 與 data 物件實體 {pwd:"123"} 傳送, 發現以 url 字串傳送之參數在伺服端要用 $_GET[] 讀取, 而用物件實體傳送的參數要用 $_POST[] 讀取, 但是用 Chrome 觀察, 發現標示為 POST. 可見混合傳送時, 只要 data 引數是物件實體, Ajax 引擎就會以 POST 方式傳送, 但 url 中的字串在 PHP 中必須以 $_GET[] 讀取, 用 $_POST[] 是讀不到的.



<!DOCTYPE html>
<html>
<head>
  <title>Ajax load test</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
  <div id="result"></div>
  <input type="button" id="load" value="load">
  <script>   
    $(function(){
      $("#load").click(function() {
        $("#result").load("test.php",
        function(responseText,textStatus,XMLHttpRequest) {
                  var msg="載入完成!\n" +
                                 "responseText=" + responseText + "\n" +
                                 "textStatus=" + textStatus + "\n" +
                                 "XMLHttpRequest=" + XMLHttpRequest + "\n";
                  alert(msg);
          }
            );
        });
      });
  </script>
</body>
</html>

此例主要是測試回呼函式是在要求的檔案被載入後才觸發, 並顯示 Ajax 引擎傳入回呼函式之引數.



<!DOCTYPE html>
<html>
<head>
  <title>Ajax load test</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
  <div id="result"></div>
  <input type="button" id="load" value="load">
  <script>   
    $(function(){
      $("#load").click(function() {
        $("#result").load("test_not_exist.php",
          function(responseText,textStatus,XMLHttpRequest) {
    var msg="載入完成!\n" +
                    "responseText=" + responseText + "\n" +
                    "textStatus=" + textStatus + "\n" +
                    "XMLHttpRequest=" + XMLHttpRequest + "\n";
            alert(msg);
    }
          );
        });
      });
  </script>
</body>
</html>

此例主要是測試當欲載入的檔案 test_not_exist.php 不存在時 (非同步請求失敗), 回呼函式仍會被觸發, 證實 load() 的回呼函式不論 Ajax 請求是否成功都會被觸發, 因為它的觸發條件是 Ajax 請求完成時 (complete). 由於載入失敗, 所以 id=result 的 div 元素內容不會更新, 而 Ajax 引擎傳入回呼函式的 responseText 為空, textStatus 為 error.

2019-12-14 補充 :

今天重新整理這份筆記, 主要是貼上原始碼.

2019-12-25 補充 :

測試完 $.ajax() 後回頭重新審視這篇, 發現上面的參數傳遞測試中漏掉了一個組合, 即參數一部分在 url 查詢字串, 另一部分在 data 查詢字串的情況, 這時 HTTP 請求會以 GET 方式傳送, 後端全部參數都要用 $_GET 捕捉, 為此增加了如下測試 6-1 :


範例 6-1 : 載入 php 檔並分別在 url 與 data 中帶參數 (GET) [看原始碼]

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <style>
    </style>
  </head>
  <body>
    <div id="result"></div>
    <input type="button" id="load" value="load">
    <script> 
      $(function(){
        $("#load").click(function() {
          $("#result").load("test.php?user=tony","pwd=123");
          });
        });
    </script>
  </body>
</html>

這樣全部組合都有了 (真是不可自拔的完美主義者!), 綜合上面測試結果, 呼叫 load() 方法時在 url 與 data 參數中 HTTP 請求參數的表示方式與送出的 HTTP 請求方法摘要如下表 :


 url 參數 data 參數 HTTP 請求 後端 PHP 讀取參數
 test.php?a=1&b=2 無 GET $_GET["a"] 與 $_GET["b"]
 test.php {a:1, b: 2} POST $_POST["a"] 與 $_POST["b"]
 test.php "a=1&b=2" GET $_GET["a"] 與 $_GET["b"]
 test.php?a=1 {b: 2} POST $_GET["a"] 與 $_POST["b"]
 test.php?a=1 "b=2" GET $_GET["a"] 與 $_GET["b"]


可見對於 load() 方法而言, 只要 data 是物件, 則 HTTP 請求一定是 POST, 後端擷取參數的方式則只與參數形式有關 : url 查詢字串攜帶的參數必須用 $_GET[] 讀取; data 如果是查詢字串也必須用 $_GET[] 讀取;  data 如果是物件則必須用 $_POST[] 讀取.

如果覺得要判斷用 $_GET[] 還是 $_POST[] 很麻煩, 則可用 $_REQUEST[], 不管參數用查詢字串或物件形式表達, $_REQUEST[] 都可以捕捉到.

2 則留言 :

匿名 提到...

$("#result").load("test.php?user=tony&pwd=123"}); //GET

是不是多一個} ??

小狐狸事務所 提到...

對, 打錯了, 已修正, 感謝您!