AJAX 如何查询并刷新页面

下面给你一个完整的 HTML + JavaScript 示例,演示如何通过 AJAX 从后端 API 查询数据,并自动刷新页面显示。

我会提供两个版本:

  1. 基础版:手动刷新(点击按钮)

  2. 自动刷新版:每隔几秒自动获取最新数据


一、前提条件

假设你的后端已经提供了以下 API(参考上一轮对话):

API 接口方法返回示例
http://服务器IP:8080/api/latest GET {"device_id":"A001","temperature":25.3,"humidity":60,"time":"2026-05-25 10:00:00"}
http://服务器IP:8080/api/history?hours=24 GET [{"temperature":25.3,"time":"..."}, {...}]

二、基础版:点击按钮刷新

完整 HTML 代码(保存为 index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IoT 数据监控面板</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 50px auto;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .card {
            background: white;
            border-radius: 10px;
            padding: 20px;
            margin-bottom: 20px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
        .data-row {
            display: flex;
            justify-content: space-between;
            padding: 10px 0;
            border-bottom: 1px solid #eee;
        }
        .label {
            font-weight: bold;
            color: #555;
        }
        .value {
            font-size: 24px;
            color: #2196F3;
        }
        .timestamp {
            color: #999;
            font-size: 14px;
            margin-top: 10px;
        }
        button {
            background-color: #2196F3;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
        }
        button:hover {
            background-color: #0b7dda;
        }
        .error {
            color: red;
            padding: 10px;
            background: #ffe6e6;
            border-radius: 5px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
        }
        th, td {
            padding: 8px;
            text-align: left;
            border-bottom: 1px solid #ddd;
        }
        th {
            background-color: #2196F3;
            color: white;
        }
    </style>
</head>
<body><h1>🌡️ 物联网传感器监控</h1><!-- 最新数据卡片 -->
<div class="card">
    <h2>📊 最新数据</h2>
    <div id="latestData">
        <div class="data-row">
            <span class="label">设备 ID:</span>
            <span id="deviceId">--</span>
        </div>
        <div class="data-row">
            <span class="label">温度:</span>
            <span id="temperature" class="value">--</span>
            <span>°C</span>
        </div>
        <div class="data-row">
            <span class="label">湿度:</span>
            <span id="humidity" class="value">--</span>
            <span>%</span>
        </div>
        <div class="timestamp">
            📅 更新时间:<span id="updateTime">--</span>
        </div>
    </div>
    <button onclick="fetchLatestData()">🔄 手动刷新</button>
</div><!-- 历史数据表格 -->
<div class="card">
    <h2>📜 历史数据(最近24小时)</h2>
    <button onclick="fetchHistoryData()" style="margin-bottom: 10px;">📋 加载历史数据</button>
    <div id="historyData">
        <table id="historyTable">
            <thead>
                <tr><th>时间</th><th>温度 (°C)</th><th>湿度 (%)</th></tr>
            </thead>
            <tbody id="historyBody">
                <tr><td colspan="3">点击上方按钮加载数据</td></tr>
            </tbody>
        </table>
    </div>
</div><script>
    // 后端 API 地址(改成你的服务器 IP 和端口)
    const API_BASE_URL = 'http://192.168.1.100:8080';  // ⚠️ 修改这里
    
    /**
     * 获取最新一条数据
     */
    async function fetchLatestData() {
        try {
            const response = await fetch(`${API_BASE_URL}/api/latest`);
            
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            
            const data = await response.json();
            
            // 更新页面显示
            document.getElementById('deviceId').textContent = data.device_id || '--';
            document.getElementById('temperature').textContent = data.temperature || '--';
            document.getElementById('humidity').textContent = data.humidity || '--';
            document.getElementById('updateTime').textContent = formatTime(data.time);
            
            console.log('最新数据已更新:', data);
        } catch (error) {
            console.error('获取最新数据失败:', error);
            document.getElementById('latestData').innerHTML += 
                '<div class="error">❌ 获取数据失败:' + error.message + '</div>';
        }
    }
    
    /**
     * 获取历史数据(最近24小时)
     */
    async function fetchHistoryData() {
        try {
            const response = await fetch(`${API_BASE_URL}/api/history?hours=24`);
            
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            
            const data = await response.json();
            
            // 渲染表格
            const tbody = document.getElementById('historyBody');
            tbody.innerHTML = '';
            
            if (data.length === 0) {
                tbody.innerHTML = '<tr><td colspan="3">暂无历史数据</td></tr>';
                return;
            }
            
            data.forEach(item => {
                const row = tbody.insertRow();
                row.insertCell(0).textContent = formatTime(item.time);
                row.insertCell(1).textContent = item.temperature + ' °C';
                row.insertCell(2).textContent = item.humidity + ' %';
            });
            
            console.log(`已加载 ${data.length} 条历史数据`);
        } catch (error) {
            console.error('获取历史数据失败:', error);
            document.getElementById('historyBody').innerHTML = 
                '<tr><td colspan="3" class="error">❌ 加载失败:' + error.message + '</td></tr>';
        }
    }
    
    /**
     * 格式化时间显示
     */
    function formatTime(timestamp) {
        if (!timestamp) return '--';
        const date = new Date(timestamp);
        return date.toLocaleString('zh-CN', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit'
        });
    }
    
    // 页面加载时自动获取最新数据
    fetchLatestData();
    
    // 可选:每 30 秒自动刷新最新数据
    // setInterval(fetchLatestData, 30000);
</script></body>
</html>

三、自动刷新版(实时监控)

在页面头部添加一个控制开关,可以启动/停止自动刷新。

修改后的 JavaScript(替换上面 <script> 部分)

 // 后端 API 地址
    const API_BASE_URL = 'http://192.168.1.100:8080';
    
    let autoRefreshInterval = null;
    let isAutoRefreshing = false;
    
    // 最新数据
    async function fetchLatestData() {
        try {
            const response = await fetch(`${API_BASE_URL}/api/latest`);
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            const data = await response.json();
            
            document.getElementById('deviceId').textContent = data.device_id || '--';
            document.getElementById('temperature').textContent = data.temperature || '--';
            document.getElementById('humidity').textContent = data.humidity || '--';
            document.getElementById('updateTime').textContent = formatTime(data.time);
            
            // 添加闪烁效果(数据更新时闪一下)
            blinkElement('latestData');
        } catch (error) {
            console.error('获取数据失败:', error);
        }
    }
    
    // 闪烁效果
    function blinkElement(elementId) {
        const element = document.getElementById(elementId);
        element.style.transition = 'background 0.2s';
        element.style.background = '#e3f2fd';
        setTimeout(() => { element.style.background = ''; }, 300);
    }
    
    // 开始自动刷新
    function startAutoRefresh() {
        if (autoRefreshInterval) clearInterval(autoRefreshInterval);
        autoRefreshInterval = setInterval(fetchLatestData, 5000); // 每5秒刷新
        isAutoRefreshing = true;
        document.getElementById('autoRefreshBtn').textContent = '⏸️ 停止自动刷新';
        document.getElementById('autoRefreshBtn').style.backgroundColor = '#f44336';
        console.log('自动刷新已启动(间隔5秒)');
    }
    
    // 停止自动刷新
    function stopAutoRefresh() {
        if (autoRefreshInterval) {
            clearInterval(autoRefreshInterval);
            autoRefreshInterval = null;
        }
        isAutoRefreshing = false;
        document.getElementById('autoRefreshBtn').textContent = '▶️ 开始自动刷新';
        document.getElementById('autoRefreshBtn').style.backgroundColor = '#2196F3';
        console.log('自动刷新已停止');
    }
    
    // 切换自动刷新
    function toggleAutoRefresh() {
        if (isAutoRefreshing) {
            stopAutoRefresh();
        } else {
            startAutoRefresh();
        }
    }
    
    // 历史数据(同上)
    async function fetchHistoryData() {
        // ... 与基础版相同
    }
    
    function formatTime(timestamp) {
        // ... 与基础版相同
    }
    
    // 页面加载时
    fetchLatestData();
    startAutoRefresh();  // 默认开启自动刷新
    
    // 页面关闭时停止自动刷新(可选)
    window.addEventListener('beforeunload', () => {
        if (autoRefreshInterval) clearInterval(autoRefreshInterval);
    });
对应修改 HTML 中的按钮区域
<div class="card">
    <h2>📊 最新数据</h2>
    <!-- ... 数据显示部分 ... -->
    <div style="display: flex; gap: 10px;">
        <button onclick="fetchLatestData()">🔄 手动刷新</button>
        <button id="autoRefreshBtn" onclick="toggleAutoRefresh()">⏸️ 停止自动刷新</button>
    </div>
</div>

四、完整的高级版(图表 + 实时曲线)

如果你想要更漂亮的图表,可以使用 EChartsChart.js

安装 Chart.js(通过 CDN)

<head> 中添加:

<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>

添加图表展示

let temperatureChart = null;
​
// 初始化图表
function initChart() {
    const ctx = document.getElementById('tempChart').getContext('2d');
    temperatureChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: [],  // 时间
            datasets: [{
                label: '温度 (°C)',
                data: [],
                borderColor: 'rgb(75, 192, 192)',
                tension: 0.1
            }]
        },
        options: {
            responsive: true,
            scales: {
                y: {
                    title: { display: true, text: '温度 (°C)' }
                }
            }
        }
    });
}
​
// 更新图表(配合历史数据)
async function updateChart() {
    const response = await fetch(`${API_BASE_URL}/api/history?hours=24`);
    const data = await response.json();
    
    const labels = data.map(item => formatTime(item.time).slice(5, 16)); // 月-日 时:分
    const temps = data.map(item => item.temperature);
    
    if (temperatureChart) {
        temperatureChart.data.labels = labels;
        temperatureChart.data.datasets[0].data = temps;
        temperatureChart.update();
    }
}
​
// 页面加载时调用
initChart();
fetchHistoryData();
setTimeout(updateChart, 500);

五、常见问题与解决

1. 跨域问题(CORS)

如果浏览器报错 Access-Control-Allow-Origin,需要在后端 Flask 中启用 CORS:

# 后端添加
from flask_cors import CORS
CORS(app)  # 允许所有跨域请求

或者安装:pip install flask-cors

2. AJAX 请求失败

  • 检查后端 API 是否正常运行:在浏览器直接访问 http://服务器IP:8080/api/latest 看是否有返回

  • 检查防火墙是否开放了 8080 端口

  • 如果是 HTTPS 页面访问 HTTP API,会被浏览器阻止(需要后端也配置 HTTPS)

3. 自动刷新频率

  • 建议间隔 3-10 秒,不要太频繁(避免服务器压力)

  • 如果需要毫秒级实时,应该用 WebSocket 而不是 AJAX 轮询

4. 页面显示优化

添加 CSS 动画让数据变化更明显:

@keyframes highlight {
    0% { background-color: #ffff99; }
    100% { background-color: transparent; }
}
.data-updated {
    animation: highlight 0.5s ease-out;
}
在 JavaScript 中:

document.getElementById('temperature').classList.add('data-updated');
setTimeout(() => {
    document.getElementById('temperature').classList.remove('data-updated');
}, 500);

六、总结

方式优点缺点适用场景
手动刷新(按钮) 简单、省资源 用户需要主动点击 数据变化不频繁
定时轮询(setInterval) 自动更新、实现简单 有延迟、浪费带宽 秒级实时性要求不高
WebSocket 真正的实时、省资源 实现复杂、需要后端支持 毫秒级实时监控

你的场景(10 秒采集一次)用 定时轮询(5 秒一次) 就足够了。


把上面的 index.html 文件放到你的 Web 服务器目录(或直接用浏览器打开),修改 API_BASE_URL 为你的实际服务器地址,就可以看到效果了。

posted @ 2026-05-25 21:15  星火撩原  阅读(8)  评论(0)    收藏  举报