JavaScript 接收并解析后端发送的 JSON 数据,同时将数据以美观的方式展示在页面上

发布于:2025-05-15 ⋅ 阅读:(15) ⋅ 点赞:(0)

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 构造函数创建连接
  • 监听 onopenonmessageonclose 和 onerror 事件
  • 提供连接 / 断开切换按钮

JSON 解析

  • 使用 JSON.parse() 解析后端发送的字符串
  • 处理嵌套 JSON 结构
  • 类型安全检查和错误处理

UI 渲染

  • 使用 Tailwind CSS 实现现代卡片式布局
  • 动态生成 HTML 内容
  • 添加消息动画和状态指示器
  • 响应式设计适配各种屏幕尺寸

用户体验优化

  • 连接状态实时显示
  • 消息接收时间戳
  • 错误提示和友好反馈
  • 平滑过渡动画

将上述代码保存为 HTML 文件后,在浏览器中打开即可使用。确保后端 WebSocket 服务在 ws://localhost:8080/websocket 可用,或根据实际情况修改连接地址。


网站公告

今日签到

点亮在社区的每一天
去签到