Appearance
17.5 AJAX 交互(无刷新)
什么是 AJAX
AJAX(Asynchronous JavaScript and XML)是一种在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术。它允许网页在后台与服务器进行数据交换,使网页能够动态更新,提高用户体验。
AJAX 的工作原理
- 用户触发事件:用户在网页上执行某个操作,如点击按钮、输入文本等
- 创建 XMLHttpRequest 对象:JavaScript 创建一个 XMLHttpRequest 对象,用于与服务器通信
- 发送请求:XMLHttpRequest 对象向服务器发送请求
- 服务器处理请求:服务器接收请求,处理数据,并返回响应
- 接收响应:XMLHttpRequest 对象接收服务器的响应
- 更新页面:JavaScript 处理响应数据,并更新网页的部分内容
使用 AJAX 的优势
- 提高用户体验:无需刷新整个页面,减少等待时间
- 减少服务器负担:只传输必要的数据,减少带宽使用
- 提高响应速度:只更新页面的部分内容,提高页面响应速度
- 增强交互性:可以实现实时数据更新和动态内容加载
PHP 实现 AJAX 交互
1. 基本 AJAX 请求
php
<?php
// ajax.php
if (isset($_POST['action'])) {
$action = $_POST['action'];
switch ($action) {
case 'get_data':
// 模拟获取数据
$data = [
'message' => 'Hello, AJAX!',
'time' => date('Y-m-d H:i:s')
];
echo json_encode($data);
break;
default:
echo json_encode(['error' => 'Invalid action']);
break;
}
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AJAX 测试</title>
</head>
<body>
<h1>AJAX 测试</h1>
<button id="get-data">获取数据</button>
<div id="result"></div>
<script>
document.getElementById('get-data').addEventListener('click', function() {
// 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
// 设置请求类型和 URL
xhr.open('POST', 'ajax.php', true);
// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 处理响应
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
document.getElementById('result').innerHTML = '<p>' + response.message + '</p><p>时间:' + response.time + '</p>';
}
};
// 发送请求
xhr.send('action=get_data');
});
</script>
</body>
</html>2. 使用 jQuery AJAX
php
<?php
// ajax.php
if (isset($_POST['action'])) {
$action = $_POST['action'];
switch ($action) {
case 'get_data':
$data = [
'message' => 'Hello, jQuery AJAX!',
'time' => date('Y-m-d H:i:s')
];
echo json_encode($data);
break;
default:
echo json_encode(['error' => 'Invalid action']);
break;
}
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>jQuery AJAX 测试</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<h1>jQuery AJAX 测试</h1>
<button id="get-data">获取数据</button>
<div id="result"></div>
<script>
$('#get-data').click(function() {
$.ajax({
url: 'ajax.php',
type: 'POST',
data: { action: 'get_data' },
dataType: 'json',
success: function(response) {
$('#result').html('<p>' + response.message + '</p><p>时间:' + response.time + '</p>');
},
error: function(xhr, status, error) {
console.error('Error:', error);
}
});
});
</script>
</body>
</html>3. 使用 Fetch API
php
<?php
// ajax.php
if (isset($_POST['action'])) {
$action = $_POST['action'];
switch ($action) {
case 'get_data':
$data = [
'message' => 'Hello, Fetch API!',
'time' => date('Y-m-d H:i:s')
];
echo json_encode($data);
break;
default:
echo json_encode(['error' => 'Invalid action']);
break;
}
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fetch API 测试</title>
</head>
<body>
<h1>Fetch API 测试</h1>
<button id="get-data">获取数据</button>
<div id="result"></div>
<script>
document.getElementById('get-data').addEventListener('click', async function() {
try {
const response = await fetch('ajax.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'action=get_data'
});
const data = await response.json();
document.getElementById('result').innerHTML = '<p>' + data.message + '</p><p>时间:' + data.time + '</p>';
} catch (error) {
console.error('Error:', error);
}
});
</script>
</body>
</html>4. 使用 Axios
php
<?php
// ajax.php
if (isset($_POST['action'])) {
$action = $_POST['action'];
switch ($action) {
case 'get_data':
$data = [
'message' => 'Hello, Axios!',
'time' => date('Y-m-d H:i:s')
];
echo json_encode($data);
break;
default:
echo json_encode(['error' => 'Invalid action']);
break;
}
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Axios 测试</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<h1>Axios 测试</h1>
<button id="get-data">获取数据</button>
<div id="result"></div>
<script>
document.getElementById('get-data').addEventListener('click', async function() {
try {
const response = await axios.post('ajax.php', { action: 'get_data' });
document.getElementById('result').innerHTML = '<p>' + response.data.message + '</p><p>时间:' + response.data.time + '</p>';
} catch (error) {
console.error('Error:', error);
}
});
</script>
</body>
</html>AJAX 最佳实践
- 使用适当的 HTTP 方法:GET 用于获取数据,POST 用于提交数据
- 处理错误:捕获和处理 AJAX 请求中的错误
- 添加加载状态:在 AJAX 请求期间显示加载指示器,提高用户体验
- 限制请求频率:避免频繁的 AJAX 请求,减少服务器负担
- 使用缓存:对于不经常变化的数据,使用缓存减少请求
- 使用 HTTPS:确保 AJAX 通信安全
- 优化数据传输:只传输必要的数据,减少数据量
- 实现超时处理:设置请求超时,避免长时间等待
实战演练
场景:实时搜索
php
<?php
// search.php
if (isset($_GET['query'])) {
$query = $_GET['query'];
// 模拟搜索结果
$products = [
['id' => 1, 'name' => 'PHP 入门教程', 'price' => 99],
['id' => 2, 'name' => 'PHP 高级编程', 'price' => 199],
['id' => 3, 'name' => 'MySQL 数据库教程', 'price' => 129],
['id' => 4, 'name' => 'JavaScript 基础', 'price' => 89],
['id' => 5, 'name' => 'HTML & CSS 教程', 'price' => 79]
];
// 过滤结果
$results = array_filter($products, function($product) use ($query) {
return strpos(strtolower($product['name']), strtolower($query)) !== false;
});
echo json_encode(['results' => array_values($results)]);
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>实时搜索</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
#search-results {
position: absolute;
width: 100%;
max-height: 200px;
overflow-y: auto;
border: 1px solid #ddd;
border-top: none;
background: white;
z-index: 1000;
}
.search-result-item {
padding: 10px;
border-bottom: 1px solid #eee;
}
.search-result-item:hover {
background-color: #f8f9fa;
}
</style>
</head>
<body>
<div class="container mt-5">
<h1>实时搜索</h1>
<div class="position-relative">
<input type="text" id="search-input" class="form-control" placeholder="搜索产品...">
<div id="search-results"></div>
</div>
</div>
<script>
let searchTimeout;
document.getElementById('search-input').addEventListener('input', function() {
clearTimeout(searchTimeout);
const query = this.value;
if (query.length < 1) {
document.getElementById('search-results').innerHTML = '';
return;
}
// 延迟搜索,减少请求频率
searchTimeout = setTimeout(async function() {
try {
const response = await fetch(`search.php?query=${encodeURIComponent(query)}`);
const data = await response.json();
let resultsHtml = '';
if (data.results.length > 0) {
data.results.forEach(product => {
resultsHtml += `
<div class="search-result-item">
<h5>${product.name}</h5>
<p>价格:¥${product.price}</p>
</div>
`;
});
} else {
resultsHtml = '<div class="search-result-item">没有找到匹配的产品</div>';
}
document.getElementById('search-results').innerHTML = resultsHtml;
} catch (error) {
console.error('Error:', error);
}
}, 300);
});
// 点击页面其他地方关闭搜索结果
document.addEventListener('click', function(event) {
if (!event.target.closest('#search-input') && !event.target.closest('#search-results')) {
document.getElementById('search-results').innerHTML = '';
}
});
</script>
</body>
</html>场景:点赞功能
php
<?php
// like.php
session_start();
// 模拟点赞数据
if (!isset($_SESSION['likes'])) {
$_SESSION['likes'] = [
1 => 10,
2 => 15,
3 => 8
];
}
if (isset($_POST['action']) && isset($_POST['post_id'])) {
$action = $_POST['action'];
$post_id = (int)$_POST['post_id'];
if ($action === 'like') {
if (isset($_SESSION['likes'][$post_id])) {
$_SESSION['likes'][$post_id]++;
} else {
$_SESSION['likes'][$post_id] = 1;
}
}
echo json_encode(['likes' => $_SESSION['likes'][$post_id]]);
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>点赞功能</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css">
</head>
<body>
<div class="container mt-5">
<h1>点赞功能</h1>
<div class="post mb-4 p-4 border">
<h3>帖子 1</h3>
<p>这是第一个帖子的内容...</p>
<div class="d-flex align-items-center">
<button class="like-btn btn btn-outline-primary" data-post-id="1">
<i class="fa fa-thumbs-up"></i> <span class="like-count">10</span>
</button>
</div>
</div>
<div class="post mb-4 p-4 border">
<h3>帖子 2</h3>
<p>这是第二个帖子的内容...</p>
<div class="d-flex align-items-center">
<button class="like-btn btn btn-outline-primary" data-post-id="2">
<i class="fa fa-thumbs-up"></i> <span class="like-count">15</span>
</button>
</div>
</div>
<div class="post mb-4 p-4 border">
<h3>帖子 3</h3>
<p>这是第三个帖子的内容...</p>
<div class="d-flex align-items-center">
<button class="like-btn btn btn-outline-primary" data-post-id="3">
<i class="fa fa-thumbs-up"></i> <span class="like-count">8</span>
</button>
</div>
</div>
</div>
<script>
document.querySelectorAll('.like-btn').forEach(button => {
button.addEventListener('click', async function() {
const postId = this.getAttribute('data-post-id');
const likeCountElement = this.querySelector('.like-count');
try {
const response = await fetch('like.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `action=like&post_id=${postId}`
});
const data = await response.json();
likeCountElement.textContent = data.likes;
// 添加点赞动画
this.classList.add('btn-primary');
this.classList.remove('btn-outline-primary');
setTimeout(() => {
this.classList.remove('btn-primary');
this.classList.add('btn-outline-primary');
}, 1000);
} catch (error) {
console.error('Error:', error);
}
});
});
</script>
</body>
</html>总结
AJAX 是一种强大的技术,它允许网页在不刷新整个页面的情况下与服务器进行数据交换,提高用户体验。PHP 提供了简单的方法来处理 AJAX 请求,通过返回 JSON 格式的数据,与前端进行交互。
在开发过程中,应该注意以下几点:
- 选择合适的 AJAX 实现方式(原生 XMLHttpRequest、jQuery、Fetch API、Axios)
- 处理错误和边界情况
- 添加加载状态,提高用户体验
- 优化请求频率和数据传输
- 确保 AJAX 通信安全
通过合理使用 AJAX,可以构建更加交互性强、响应速度快的 Web 应用程序,提高用户体验和满意度。
