如何使用Ajax实现页面无刷新自动获取消息?附相关SQL查询代码
如何用Ajax实现无刷新自动获取聊天消息?
嘿,我来帮你搞定这个需求!咱们分后端接口编写和前端Ajax实现两部分来弄,同时还会优化你原代码里的问题(比如SQL注入风险、未读消息范围不准确的问题),一步步来:
1. 后端编写API接口
首先你需要一个后端接口,用来返回当前用户的聊天记录和未读消息数(把两个需求合并成一个接口更高效)。创建一个get_chat.php文件,注意必须修复原代码的SQL注入风险,改用mysqli预处理语句:
<?php // 数据库连接(假设你已经有合法的$con连接,实际使用时要处理连接错误) session_start(); // 这里假设用户登录后,邮箱存在session中(避免直接通过GET/POST传参被篡改) $user_email = $_SESSION['logged_in_email']; // 1. 获取当前用户与管理员的聊天记录(按时间正序返回,方便前端渲染) $chat_sql = "SELECT * FROM `chat` WHERE (fromthe = ? AND tothe='theadmin') UNION ALL SELECT * FROM `chat` WHERE (fromthe='theadmin' AND tothe=?) ORDER BY id ASC"; $chat_stmt = mysqli_prepare($con, $chat_sql); mysqli_stmt_bind_param($chat_stmt, "ss", $user_email, $user_email); mysqli_stmt_execute($chat_stmt); $chat_result = mysqli_stmt_get_result($chat_stmt); $chat_messages = []; while ($row = mysqli_fetch_assoc($chat_result)) { $chat_messages[] = $row; } // 2. 获取当前用户收到的未读消息数(仅统计管理员发给当前用户的未读消息) $unread_sql = "SELECT COUNT(*) as unread_count FROM chat WHERE fromthe='theadmin' AND tothe=? AND status=0"; $unread_stmt = mysqli_prepare($con, $unread_sql); mysqli_stmt_bind_param($unread_stmt, "s", $user_email); mysqli_stmt_execute($unread_stmt); $unread_result = mysqli_stmt_get_result($unread_stmt); $unread_count = mysqli_fetch_assoc($unread_result)['unread_count']; // 返回JSON格式的响应数据 header('Content-Type: application/json'); echo json_encode([ 'messages' => $chat_messages, 'unread_count' => $unread_count ]); // 关闭连接 mysqli_close($con); ?>
注意:你原来的未读消息查询
SELECT status FROM chat WHERE status=0太宽泛了,会查询所有用户的未读消息,这里改成了仅统计管理员发给当前用户的未读消息,逻辑更合理。
2. 前端实现Ajax自动请求与渲染
前端需要做两件事:定时请求后端接口获取数据,然后更新聊天区域和未读提示。这里用原生JavaScript实现(无需依赖jQuery,更轻量):
先准备HTML结构
<!-- 聊天消息容器 --> <div id="chat-container" style="height: 400px; overflow-y: auto; border: 1px solid #eee; padding: 10px;"></div> <!-- 未读消息提示角标 --> <div id="unread-badge" style="display: none; background: red; color: white; padding: 2px 6px; border-radius: 50%;">0</div>
然后是JavaScript逻辑
// 获取页面元素 const chatContainer = document.getElementById('chat-container'); const unreadBadge = document.getElementById('unread-badge'); // 定时刷新间隔(3秒一次,可根据需求调整) const refreshGap = 3000; // 渲染聊天消息的函数 function renderMessages(messages) { // 清空容器(如果想优化性能,可以只添加新消息,这里先做简单实现) chatContainer.innerHTML = ''; messages.forEach(msg => { // 判断消息发送者,添加不同样式 const isAdminMsg = msg.fromthe === 'theadmin'; const msgClass = isAdminMsg ? 'admin-msg' : 'user-msg'; const senderName = isAdminMsg ? '管理员' : '我'; const msgElement = document.createElement('div'); msgElement.className = `chat-item ${msgClass}`; msgElement.innerHTML = ` <div class="sender">${senderName}</div> <div class="content">${msg.content}</div> <div class="time">${msg.created_at}</div> <!-- 假设你有created_at字段记录消息时间 --> `; chatContainer.appendChild(msgElement); }); // 自动滚动到最新消息 chatContainer.scrollTop = chatContainer.scrollHeight; } // 更新未读消息提示 function updateUnreadCount(count) { if (count > 0) { unreadBadge.textContent = count; unreadBadge.style.display = 'inline-block'; } else { unreadBadge.style.display = 'none'; } } // 发送Ajax请求获取聊天数据 function fetchChatData() { const xhr = new XMLHttpRequest(); xhr.open('GET', 'get_chat.php', true); xhr.onload = function() { if (this.status === 200) { try { const data = JSON.parse(this.responseText); renderMessages(data.messages); updateUnreadCount(data.unread_count); } catch (err) { console.error('解析聊天数据失败:', err); } } else { console.error('请求聊天数据失败,状态码:', this.status); } }; xhr.onerror = function() { console.error('网络请求出错,请检查接口地址'); }; xhr.send(); } // 页面加载时先获取一次数据,之后定时刷新 window.onload = function() { fetchChatData(); setInterval(fetchChatData, refreshGap); };
3. 可选优化建议
- 仅加载新消息:不用每次清空重渲染,可以记录最后一条消息的ID,下次请求时只获取ID大于该值的消息,减少数据传输和渲染开销。
- 标记消息已读:当用户打开聊天页面时,发送Ajax请求调用另一个接口(比如
mark_as_read.php),把管理员发给当前用户的未读消息status更新为1。 - 实时性优化:如果需要更实时的聊天体验,可以用长轮询或者WebSocket替代定时器,减少无效请求。
内容的提问来源于stack exchange,提问作者Navas Naz
相关产品推荐
相关产品推荐

