jQuery Ajax
Ajax(Asynchronous JavaScript and XML)是一種在不重新載入整個頁面的情況下,與伺服器交換資料並更新部分網頁內容的技術。jQuery 提供了簡潔且功能強大的 Ajax 方法。
$.ajax() - 核心方法
$.ajax() 是 jQuery Ajax 的核心方法,其他簡便方法都是基於它的封裝。
基本語法
$.ajax({
url: '/api/data',
method: 'GET',
success: function (data) {
console.log('成功:', data);
},
error: function (xhr, status, error) {
console.log('錯誤:', error);
},
});
完整範例
$.ajax({
url: '/api/users',
method: 'POST',
data: {
name: 'John',
email: 'john@example.com',
},
dataType: 'json',
contentType: 'application/x-www-form-urlencoded',
timeout: 5000,
headers: {
'X-Custom-Header': 'value',
},
beforeSend: function (xhr) {
console.log('即將發送請求');
},
success: function (data, status, xhr) {
console.log('成功:', data);
},
error: function (xhr, status, error) {
console.log('錯誤:', error);
},
complete: function (xhr, status) {
console.log('請求完成');
},
});
常用設定選項
| 選項 | 說明 |
|---|---|
url | 請求的 URL |
method / type | HTTP 方法(GET、POST、PUT、DELETE 等) |
data | 發送的資料 |
dataType | 預期的回應資料類型(json、xml、html、text、script) |
contentType | 發送資料的內容類型 |
headers | 自訂請求標頭 |
timeout | 超時時間(毫秒) |
cache | 是否快取(預設 true,dataType 為 script/jsonp 時為 false) |
async | 是否非同步(預設 true,強烈建議不要設為 false) |
processData | 是否自動將 data 轉為查詢字串(預設 true) |
回呼函式
| 回呼 | 說明 |
|---|---|
beforeSend(xhr) | 發送請求前呼叫 |
success(data, status, xhr) | 請求成功時呼叫 |
error(xhr, status, error) | 請求失敗時呼叫 |
complete(xhr, status) | 請求完成時呼叫(不論成功或失敗) |
簡便方法
$.get()
發送 GET 請求:
// 基本用法
$.get('/api/users', function (data) {
console.log(data);
});
// 帶參數
$.get('/api/users', { page: 1, limit: 10 }, function (data) {
console.log(data);
});
// 指定資料類型
$.get(
'/api/users',
{ page: 1 },
function (data) {
console.log(data);
},
'json'
);
$.post()
發送 POST 請求:
// 基本用法
$.post('/api/users', { name: 'John', email: 'john@example.com' }, function (data) {
console.log('已建立:', data);
});
// 指定資料類型
$.post(
'/api/users',
formData,
function (data) {
console.log(data);
},
'json'
);
$.getJSON()
發送 GET 請求並預期 JSON 回應:
$.getJSON('/api/users', function (data) {
console.log(data); // 已自動解析為 JavaScript 物件
});
// 帶參數
$.getJSON('/api/users', { id: 123 }, function (data) {
console.log(data);
});
$.getScript()
載入並執行 JavaScript 檔案:
$.getScript('/js/plugin.js', function () {
console.log('Script 已載入並執行');
// 現在可以使用 plugin.js 中定義的函式
});
load()
載入 HTML 並插入到元素中:
// 載入整個檔案
$('#content').load('/pages/about.html');
// 載入檔案的部分內容
$('#content').load('/pages/about.html #main');
// 帶回呼函式
$('#content').load('/pages/about.html', function (response, status, xhr) {
if (status === 'error') {
console.log('載入失敗');
}
});
// 帶資料(會改用 POST)
$('#content').load('/pages/about.html', { section: 'intro' });
jqXHR 與 Promise
從 jQuery 1.5 開始,所有 Ajax 方法都返回一個 jqXHR 物件,它實作了 Promise 介面。
Promise 方法
var jqxhr = $.ajax('/api/users');
// 成功時
jqxhr.done(function (data, status, xhr) {
console.log('成功:', data);
});
// 失敗時
jqxhr.fail(function (xhr, status, error) {
console.log('失敗:', error);
});
// 完成時(不論成功或失敗)
jqxhr.always(function () {
console.log('請求完成');
});
鏈式寫法
$.ajax('/api/users')
.done(function (data) {
console.log('成功:', data);
})
.fail(function (xhr, status, error) {
console.log('失敗:', error);
})
.always(function () {
console.log('完成');
});
使用 then()
$.ajax('/api/users').then(
function (data) {
// 成功
console.log('成功:', data);
},
function (xhr, status, error) {
// 失敗
console.log('失敗:', error);
}
);
Promise 鏈
$.ajax('/api/user/1')
.then(function (user) {
console.log('使用者:', user);
return $.ajax('/api/posts?userId=' + user.id);
})
.then(function (posts) {
console.log('文章:', posts);
return $.ajax('/api/comments?postId=' + posts[0].id);
})
.then(function (comments) {
console.log('留言:', comments);
})
.fail(function (error) {
console.log('發生錯誤:', error);
});
$.when() - 並行請求
同時發送多個請求,等待全部完成:
$.when($.ajax('/api/users'), $.ajax('/api/posts'), $.ajax('/api/comments'))
.done(function (usersResult, postsResult, commentsResult) {
// 每個結果是 [data, status, xhr] 陣列
var users = usersResult[0];
var posts = postsResult[0];
var comments = commentsResult[0];
console.log('使用者:', users);
console.log('文章:', posts);
console.log('留言:', comments);
})
.fail(function () {
console.log('至少一個請求失敗');
});
表單序列化
serialize()
將表單資料序列化為查詢字串格式:
// 結果如:name=John&email=john%40example.com
var queryString = $('form').serialize();
// 用於 Ajax
$.post('/api/submit', $('form').serialize(), function (response) {
console.log(response);
});
serializeArray()
將表單資料序列化為物件陣列:
var formData = $('form').serializeArray();
// [{name: "field1", value: "value1"}, {name: "field2", value: "value2"}]
// 轉換為物件
var formObject = {};
$.each($('form').serializeArray(), function (i, field) {
formObject[field.name] = field.value;
});
Ajax 事件
局部事件
透過 $.ajax() 的回呼函式設定:
$.ajax({
url: '/api/data',
beforeSend: function () {
console.log('發送前');
},
success: function (data) {
console.log('成功');
},
error: function () {
console.log('錯誤');
},
complete: function () {
console.log('完成');
},
});
全域事件
在任何元素上綁定,所有 Ajax 請求都會觸發:
// 任何 Ajax 請求開始時
$(document).on('ajaxStart', function () {
$('#loading').show();
});
// 任何 Ajax 請求完成時
$(document).on('ajaxStop', function () {
$('#loading').hide();
});
// 其他全域事件
$(document).on('ajaxSend', function (event, xhr, settings) {
console.log('即將發送:', settings.url);
});
$(document).on('ajaxSuccess', function (event, xhr, settings, data) {
console.log('成功:', settings.url);
});
$(document).on('ajaxError', function (event, xhr, settings, error) {
console.log('錯誤:', settings.url, error);
});
$(document).on('ajaxComplete', function (event, xhr, settings) {
console.log('完成:', settings.url);
});
事件觸發順序
ajaxStart(第一個請求開始時)beforeSend(局部)ajaxSend(全域)success或error(局部)ajaxSuccess或ajaxError(全域)complete(局部)ajaxComplete(全域)ajaxStop(所有請求完成時)
關閉全域事件
$.ajax({
url: '/api/data',
global: false, // 不觸發全域事件
success: function (data) {
console.log(data);
},
});
發送 JSON 資料
$.ajax({
url: '/api/users',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
name: 'John',
email: 'john@example.com',
}),
success: function (data) {
console.log(data);
},
});
發送 FormData(檔案上傳)
var formData = new FormData();
formData.append('file', $('#fileInput')[0].files[0]);
formData.append('name', 'document');
$.ajax({
url: '/api/upload',
method: 'POST',
data: formData,
processData: false, // 不處理資料
contentType: false, // 不設定內容類型
success: function (data) {
console.log('上傳成功:', data);
},
});
全域設定
$.ajaxSetup()
設定所有 Ajax 請求的預設值:
$.ajaxSetup({
headers: {
Authorization: 'Bearer ' + token,
},
timeout: 10000,
dataType: 'json',
});
// 之後的請求都會使用這些預設值
$.get('/api/users', function (data) {
console.log(data);
});
注意:
$.ajaxSetup() 會影響所有 Ajax 請求,包括第三方程式碼的請求,請謹慎使用。錯誤處理
$.ajax({
url: '/api/data',
method: 'GET',
})
.done(function (data) {
console.log('成功:', data);
})
.fail(function (xhr, status, error) {
// status 可能的值:timeout, error, abort, parsererror
console.log('狀態碼:', xhr.status);
console.log('狀態文字:', xhr.statusText);
console.log('錯誤類型:', status);
console.log('錯誤訊息:', error);
// 嘗試解析錯誤回應
try {
var response = JSON.parse(xhr.responseText);
console.log('伺服器錯誤訊息:', response.message);
} catch (e) {
console.log('回應內容:', xhr.responseText);
}
});
跨域請求 (CORS)
瀏覽器的同源政策會阻止跨域請求。若伺服器支援 CORS,jQuery Ajax 可以正常運作:
// 伺服器需要設定正確的 CORS 標頭
$.ajax({
url: 'https://api.example.com/data',
method: 'GET',
xhrFields: {
withCredentials: true, // 如需傳送 cookies
},
success: function (data) {
console.log(data);
},
});
JSONP(舊式跨域方案)
$.ajax({
url: 'https://api.example.com/data',
dataType: 'jsonp',
jsonpCallback: 'handleResponse',
success: function (data) {
console.log(data);
},
});
JSONP 只支援 GET 請求,且存在安全風險。現代應用應優先使用 CORS。
實用範例
載入更多
var page = 1;
var loading = false;
$('#loadMore').on('click', function () {
if (loading) return;
loading = true;
$(this).text('載入中...');
$.get('/api/posts', { page: ++page }, function (posts) {
$.each(posts, function (i, post) {
$('#posts').append('<div class="post">' + post.title + '</div>');
});
}).always(function () {
loading = false;
$('#loadMore').text('載入更多');
});
});
自動儲存
var saveTimer;
$('textarea').on('input', function () {
clearTimeout(saveTimer);
saveTimer = setTimeout(function () {
$.post('/api/save', {
content: $('textarea').val(),
}).done(function () {
$('#status').text('已儲存').fadeIn().delay(1000).fadeOut();
});
}, 1000); // 停止輸入 1 秒後自動儲存
});
搜尋建議
var searchTimer;
$('#search').on('input', function () {
var query = $(this).val();
clearTimeout(searchTimer);
if (query.length < 2) {
$('#suggestions').hide();
return;
}
searchTimer = setTimeout(function () {
$.get('/api/search', { q: query }, function (results) {
var $suggestions = $('#suggestions').empty();
$.each(results, function (i, item) {
$suggestions.append('<div class="suggestion">' + item + '</div>');
});
$suggestions.show();
});
}, 300);
});