JavaScript 接收并解析后端发送的 JSON 数据,同时将数据以美观的方式展示在页面上
JavaScript 实现代码
这段代码包含 WebSocket 连接管理、JSON 解析和 UI 渲染逻辑:
// WebSocket 连接管理
let socket;
const messageContainer = document.getElementById('message-container');
const socketStatus = document.getElementById('socket-status');
const connectBtn = document.getElementById('connect-btn');
const lastUpdate = document.getElementById('last-update');// 连接 WebSocket
function connectWebSocket() {// 关闭现有连接(如果存在)if (socket && socket.readyState !== WebSocket.CLOSED) {socket.close();}// 创建新连接socket = new WebSocket('ws://localhost:8080/websocket');// 更新 UI 状态socketStatus.innerHTML = '<i class="fa fa-circle-o-notch fa-spin mr-2"></i>连接中...';socketStatus.classList.remove('disconnected', 'connected');connectBtn.disabled = true;connectBtn.innerHTML = '<i class="fa fa-circle-o-notch fa-spin mr-2"></i>连接中...';// 监听连接成功socket.onopen = () => {messageContainer.innerHTML = '';socketStatus.innerHTML = '<i class="fa fa-check-circle mr-2"></i>已连接';socketStatus.classList.add('connected');connectBtn.innerHTML = '<i class="fa fa-plug mr-2"></i>断开连接';connectBtn.disabled = false;connectBtn.classList.remove('bg-primary');connectBtn.classList.add('bg-red-500', 'hover:bg-red-600');appendSystemMessage('WebSocket 连接已建立');};// 监听消息接收socket.onmessage = (event) => {try {// 解析 JSON 数据const jsonData = JSON.parse(event.data);// 更新最后更新时间const now = new Date();lastUpdate.textContent = now.toLocaleString();// 格式化显示数据const messageDiv = document.createElement('div');messageDiv.className = 'message-card';messageDiv.style.opacity = '0';messageDiv.style.transform = 'translateY(10px)';messageDiv.style.transition = 'opacity 0.3s ease, transform 0.3s ease';// 动态生成内容let contentHtml = '';for (const [key, value] of Object.entries(jsonData)) {if (typeof value === 'object' && value !== null) {// 嵌套对象处理contentHtml += `<p><strong>${formatKey(key)}:</strong></p>`;contentHtml += '<div class="ml-4 bg-gray-50 p-3 rounded my-2">';for (const [nestedKey, nestedValue] of Object.entries(value)) {contentHtml += `<p class="text-sm"><strong>${formatKey(nestedKey)}:</strong> ${formatValue(nestedValue)}</p>`;}contentHtml += '</div>';} else {// 普通字段处理contentHtml += `<p><strong>${formatKey(key)}:</strong> ${formatValue(value)}</p>`;}}messageDiv.innerHTML = contentHtml;messageContainer.prepend(messageDiv);// 添加动画效果setTimeout(() => {messageDiv.style.opacity = '1';messageDiv.style.transform = 'translateY(0)';}, 10);} catch (error) {console.error('解析 JSON 失败:', error);appendError(`解析消息失败: ${error.message}`);}};// 监听连接关闭socket.onclose = (event) => {socketStatus.innerHTML = '<i class="fa fa-times-circle mr-2"></i>已断开';socketStatus.classList.remove('connected');socketStatus.classList.add('disconnected');connectBtn.innerHTML = '<i class="fa fa-plug mr-2"></i>连接';connectBtn.disabled = false;connectBtn.classList.remove('bg-red-500', 'hover:bg-red-600');connectBtn.classList.add('bg-primary');appendSystemMessage(`WebSocket 连接已关闭 (代码: ${event.code})`);};// 监听错误socket.onerror = (error) => {console.error('WebSocket 错误:', error);appendError(`WebSocket 错误: ${error.message}`);};
}// 格式化键名(将 camelCase 转为空格分隔的标题格式)
function formatKey(key) {return key.replace(/([A-Z])/g, ' $1').replace(/^./, (str) => str.toUpperCase());
}// 格式化值(处理特殊类型)
function formatValue(value) {if (typeof value === 'number' && !isNaN(value)) {return value;} else if (typeof value === 'boolean') {return value ? '<span class="text-green-600">是</span>' : '<span class="text-red-600">否</span>';} else if (value === null || value === undefined) {return '<span class="text-gray-400">null</span>';} else if (typeof value === 'string') {// 尝试解析为日期const date = new Date(value);if (!isNaN(date.getTime())) {return date.toLocaleString();}return value;}return JSON.stringify(value);
}// 添加系统消息
function appendSystemMessage(message) {const systemMessage = document.createElement('div');systemMessage.className = 'text-center text-gray-500 italic py-2';systemMessage.innerHTML = `<i class="fa fa-info-circle mr-1"></i> ${message}`;messageContainer.prepend(systemMessage);
}// 添加错误消息
function appendError(message) {const errorDiv = document.createElement('div');errorDiv.className = 'error-card';errorDiv.innerHTML = `<p><i class="fa fa-exclamation-triangle mr-1"></i> ${message}</p>`;messageContainer.prepend(errorDiv);
}// 连接按钮事件
connectBtn.addEventListener('click', () => {if (socket && socket.readyState === WebSocket.OPEN) {socket.close();} else {connectWebSocket();}
});// 页面加载时自动连接
window.addEventListener('load', connectWebSocket);
HTML 结构(需配合上述 JS 使用)
完整的 HTML 页面结构,包含 Tailwind CSS 和 Font Awesome 引入:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket JSON 消息接收</title><script src="https://cdn.tailwindcss.com"></script><link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet"><script>tailwind.config = {theme: {extend: {colors: {primary: '#165DFF',secondary: '#36CFC9',neutral: '#F5F7FA',dark: '#1D2129',},fontFamily: {inter: ['Inter', 'system-ui', 'sans-serif'],},}}}</script><style type="text/tailwindcss">@layer utilities {.content-auto {content-visibility: auto;}.message-card {@apply bg-white rounded-lg shadow-md p-4 mb-4 transition-all duration-300 hover:shadow-lg border-l-4 border-primary;}.error-card {@apply bg-red-50 border-l-4 border-red-400 text-red-700 p-4 mb-4 rounded-r shadow-md;}.socket-status {@apply fixed top-4 right-4 px-4 py-2 rounded-full text-sm font-medium transition-all duration-300 z-50;}.socket-status.connected {@apply bg-green-100 text-green-800 border border-green-400;}.socket-status.disconnected {@apply bg-red-100 text-red-800 border border-red-400;}}</style>
</head>
<body class="bg-gray-50 font-inter text-dark min-h-screen"><div class="container mx-auto px-4 py-8 max-w-5xl"><header class="mb-8"><h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-primary mb-2">WebSocket JSON 消息接收</h1><p class="text-gray-600">实时接收并解析后端发送的 JSON 数据</p></header><!-- 状态指示器 --><div id="socket-status" class="socket-status disconnected"><i class="fa fa-circle-o mr-2"></i>未连接</div><!-- 消息容器 --><div class="bg-white rounded-xl shadow-lg p-6 mb-6"><h2 class="text-xl font-semibold mb-4 flex items-center"><i class="fa fa-comments-o text-primary mr-2"></i>消息记录</h2><div id="message-container" class="space-y-4 max-h-[60vh] overflow-y-auto p-2"><div class="text-center text-gray-500 italic py-8">等待 WebSocket 连接...</div></div></div><!-- 控制按钮 --><div class="flex justify-between items-center"><button id="connect-btn" class="px-6 py-3 bg-primary hover:bg-primary/90 text-white rounded-lg shadow transition-all duration-300 flex items-center"><i class="fa fa-plug mr-2"></i>连接</button><div class="text-sm text-gray-500"><i class="fa fa-clock-o mr-1"></i>最后更新: <span id="last-update">-</span></div></div></div><!-- 这里插入上面的 JavaScript 代码 --><script>// 上面的 JS 代码放在这里</script>
</body>
</html>
核心功能说明
WebSocket 连接管理:
- 使用
WebSocket
构造函数创建连接 - 监听
onopen
、onmessage
、onclose
和onerror
事件 - 提供连接 / 断开切换按钮
JSON 解析:
- 使用
JSON.parse()
解析后端发送的字符串 - 处理嵌套 JSON 结构
- 类型安全检查和错误处理
UI 渲染:
- 使用 Tailwind CSS 实现现代卡片式布局
- 动态生成 HTML 内容
- 添加消息动画和状态指示器
- 响应式设计适配各种屏幕尺寸
用户体验优化:
- 连接状态实时显示
- 消息接收时间戳
- 错误提示和友好反馈
- 平滑过渡动画
将上述代码保存为 HTML 文件后,在浏览器中打开即可使用。确保后端 WebSocket 服务在 ws://localhost:8080/websocket
可用,或根据实际情况修改连接地址。