AJAX 如何查询并刷新页面
我会提供两个版本:
-
基础版:手动刷新(点击按钮)
-
自动刷新版:每隔几秒自动获取最新数据
一、前提条件
假设你的后端已经提供了以下 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>
四、完整的高级版(图表 + 实时曲线)
如果你想要更漂亮的图表,可以使用 ECharts 或 Chart.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 秒一次) 就足够了。
把上面的

浙公网安备 33010602011771号