PHP+AJAX实现MySQL实时表格展示:解决JS计时器不重置及语法错误
解决PHP+AJAX实时展示MySQL数据并维持独立计时器的问题
你的需求回顾
你想要实现的是:
- 在PHP页面的表格里展示MySQL查询结果,第一列是数据库数据,第二列是独立的JavaScript计时器
- 数据库新增数据时自动在表格中显示,数据超过60秒未更新(不再出现在查询结果里)时自动移除
- 每次查询数据库时,已存在的行计时器不重置
你当前遇到的问题
前端AJAX代码里直接在JavaScript函数中插入HTML和PHP代码,导致语法错误(unexpected token <),而且逻辑上也有问题——前端无法解析PHP代码,必须通过AJAX拿到JSON数据后用JavaScript动态生成DOM元素。
一、先修正PHP后端代码
你的PHP代码有几个小问题,先调整一下:
<?php header('Content-type: application/json'); $servername = "localhost"; $username = "user"; $password = "password"; $dbname = "test"; // 创建连接 $conn = new mysqli($servername, $username, $password, $dbname); // 检查连接 if ($conn->connect_error) { die(json_encode(['error' => "Connection failed: " . $conn->connect_error])); } $sql = "SELECT * FROM ( SELECT beacon, location, COUNT(location) AS counter FROM `track` WHERE `date` = CURDATE() AND `time` > NOW() - INTERVAL 60 SECOND GROUP BY beacon ) AS SubQueryTable ORDER BY beacon + 0 ASC;"; // 只执行一次查询即可,不要重复赋值 $result = mysqli_query($conn, $sql); $rows = array(); while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; } echo json_encode($rows); $conn->close(); ?>
这里主要修正了:
- 移除了重复的查询语句
- 把连接错误也用JSON格式返回,方便前端处理
二、重构前端HTML/JavaScript代码
核心思路是:
- 定时通过AJAX获取最新的JSON数据
- 对比当前表格中的数据和新数据,新增的行添加到表格,消失的行从表格移除
- 为每个行维护独立的计时器,存储每个beacon对应的计时状态,避免全局计时器导致所有行同步更新
完整的前端代码:
<!DOCTYPE html> <html> <head> <title>实时数据追踪</title> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <style> table { border-collapse: collapse; width: 500px; margin: 20px auto; } th, td { border: 1px solid #ddd; padding: 8px; text-align: center; } th { background-color: #f2f2f2; } </style> </head> <body> <table id="dataTable"> <thead> <tr> <th>Beacon</th> <th>计时器</th> </tr> </thead> <tbody></tbody> </table> <script> // 存储每个beacon的计时器状态:key是beacon,value是{ timerId: 计时器ID, seconds: 当前秒数 } const timerMap = {}; // 存储当前表格中存在的beacon集合,用于对比更新 let currentBeacons = new Set(); // 格式化数字为两位(补0) function pad(val) { return val > 9 ? val : `0${val}`; } // 更新单个行的计时器 function updateTimer(beacon) { const timerData = timerMap[beacon]; if (!timerData) return; timerData.seconds++; const minutes = pad(Math.floor(timerData.seconds / 60)); const seconds = pad(timerData.seconds % 60); $(`#row-${beacon} .minutes`).text(minutes); $(`#row-${beacon} .seconds`).text(seconds); } // 渲染表格数据 function renderTable(newData) { const newBeacons = new Set(newData.map(item => item.beacon)); // 1. 移除不再存在的行 currentBeacons.forEach(beacon => { if (!newBeacons.has(beacon)) { // 清除对应的计时器 clearInterval(timerMap[beacon].timerId); delete timerMap[beacon]; // 删除表格行 $(`#row-${beacon}`).remove(); } }); // 2. 添加新增的行 newData.forEach(item => { if (!currentBeacons.has(item.beacon)) { // 创建表格行 const row = ` <tr id="row-${item.beacon}" style="background-color: ${item.location}"> <td>${item.beacon}</td> <td> <span class='minutes'>00</span>:<span class='seconds'>00</span> </td> </tr> `; $('#dataTable tbody').append(row); // 初始化计时器 const seconds = 0; const timerId = setInterval(() => updateTimer(item.beacon), 1000); timerMap[item.beacon] = { timerId, seconds }; } }); // 更新当前存在的beacon集合 currentBeacons = newBeacons; } // 定时获取数据并更新表格 function fetchAndUpdate() { $.get('vendor/fetch.php', function(response) { // 处理可能的错误 if (response.error) { console.error('获取数据失败:', response.error); return; } renderTable(response); }).fail(function() { console.error('AJAX请求失败'); }); } // 初始化:第一次加载数据,然后每1秒刷新一次(不要太频繁,避免给数据库太大压力) fetchAndUpdate(); setInterval(fetchAndUpdate, 1000); </script> </body> </html>
关键逻辑说明
- 计时器独立维护:用
timerMap对象存储每个beacon的计时器ID和当前秒数,确保每个行的计时器独立运行,不会因为查询刷新而重置。 - 数据对比更新:通过
currentBeacons集合对比新旧数据,只增删变化的行,而不是每次都清空表格重新渲染,提升性能。 - 错误处理:添加了AJAX请求失败和后端返回错误的处理逻辑,方便调试。
内容的提问来源于stack exchange,提问作者Avalon Parkes-barton
相关产品推荐
相关产品推荐

