Skip to content

17.5 AJAX 交互(无刷新)

什么是 AJAX

AJAX(Asynchronous JavaScript and XML)是一种在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术。它允许网页在后台与服务器进行数据交换,使网页能够动态更新,提高用户体验。

AJAX 的工作原理

  1. 用户触发事件:用户在网页上执行某个操作,如点击按钮、输入文本等
  2. 创建 XMLHttpRequest 对象:JavaScript 创建一个 XMLHttpRequest 对象,用于与服务器通信
  3. 发送请求:XMLHttpRequest 对象向服务器发送请求
  4. 服务器处理请求:服务器接收请求,处理数据,并返回响应
  5. 接收响应:XMLHttpRequest 对象接收服务器的响应
  6. 更新页面: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 最佳实践

  1. 使用适当的 HTTP 方法:GET 用于获取数据,POST 用于提交数据
  2. 处理错误:捕获和处理 AJAX 请求中的错误
  3. 添加加载状态:在 AJAX 请求期间显示加载指示器,提高用户体验
  4. 限制请求频率:避免频繁的 AJAX 请求,减少服务器负担
  5. 使用缓存:对于不经常变化的数据,使用缓存减少请求
  6. 使用 HTTPS:确保 AJAX 通信安全
  7. 优化数据传输:只传输必要的数据,减少数据量
  8. 实现超时处理:设置请求超时,避免长时间等待

实战演练

场景:实时搜索

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 应用程序,提高用户体验和满意度。

© 2026 编程马·菜鸟教程 版权所有