1. 气泡动画:消息从发送者头像位置“飞入”对话框。
  2. 打字指示器:模拟对方正在输入的动画效果。
  3. 流畅的滚动:新消息出现时,对话框自动滚动到底部。
  4. 现代化设计:采用了类似微信或 Slack 的视觉风格。

下面是完整的实现代码,您可以直接复制到一个 HTML 文件中在浏览器中打开查看效果。

最终效果预览


完整代码 (HTML + CSS + JavaScript)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">JS 在线聊天对话框特效</title>
    <style>
        /* --- 全局样式 --- */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            background-color: #f0f2f5;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            color: #333;
        }
        /* --- 主容器 --- */
        .chat-container {
            width: 380px;
            height: 600px;
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }
        /* --- 对话框头部 --- */
        .chat-header {
            padding: 15px 20px;
            background-color: #007bff;
            color: white;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        .chat-header .user-info {
            display: flex;
            align-items: center;
        }
        .chat-header .avatar {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background-color: #fff;
            margin-right: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
            color: #007bff;
        }
        /* --- 消息列表区域 --- */
        .chat-messages {
            flex: 1;
            padding: 20px;
            overflow-y: auto;
            display: flex;
            flex-direction: column;
            gap: 15px;
        }
        /* --- 消息气泡样式 --- */
        .message {
            display: flex;
            max-width: 70%;
            opacity: 0;
            transform: translateY(20px);
            animation: fadeInUp 0.3s ease forwards;
        }
        @keyframes fadeInUp {
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        /* --- 接收到的消息 --- */
        .message.received {
            align-self: flex-start;
        }
        .message.received .bubble {
            background-color: #e9e9eb;
            color: #333;
            border-radius: 18px 18px 18px 2px;
        }
        /* --- 发送的消息 --- */
        .message.sent {
            align-self: flex-end;
            flex-direction: row-reverse;
        }
        .message.sent .bubble {
            background-color: #007bff;
            color: white;
            border-radius: 18px 18px 2px 18px;
        }
        .bubble {
            padding: 12px 16px;
            font-size: 14px;
            line-height: 1.4;
            word-wrap: break-word;
        }
        /* --- 输入区域 --- */
        .chat-input-area {
            padding: 15px;
            border-top: 1px solid #eee;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        .chat-input-area input {
            flex: 1;
            padding: 10px 15px;
            border: 1px solid #ddd;
            border-radius: 20px;
            outline: none;
            font-size: 14px;
            transition: border-color 0.3s;
        }
        .chat-input-area input:focus {
            border-color: #007bff;
        }
        .send-button {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background-color: #007bff;
            color: white;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background-color 0.3s;
        }
        .send-button:hover {
            background-color: #0056b3;
        }
        /* --- 打字指示器 --- */
        .typing-indicator {
            display: none;
            align-self: flex-start;
            padding: 10px 16px;
            background-color: #e9e9eb;
            border-radius: 18px 18px 18px 2px;
        }
        .typing-indicator span {
            height: 8px;
            width: 8px;
            background-color: #999;
            display: inline-block;
            border-radius: 50%;
            margin: 0 2px;
            animation: typing 1.4s infinite;
        }
        .typing-indicator span:nth-child(2) {
            animation-delay: 0.2s;
        }
        .typing-indicator span:nth-child(3) {
            animation-delay: 0.4s;
        }
        @keyframes typing {
            0%, 60%, 100% {
                transform: translateY(0);
            }
            30% {
                transform: translateY(-10px);
            }
        }
    </style>
</head>
<body>
    <div class="chat-container">
        <div class="chat-header">
            <div class="user-info">
                <div class="avatar">AI</div>
                <span>智能助手</span>
            </div>
            <span>在线</span>
        </div>
        <div class="chat-messages" id="chatMessages">
            <!-- 消息将在这里动态生成 -->
        </div>
        <div class="typing-indicator" id="typingIndicator">
            <span></span>
            <span></span>
            <span></span>
        </div>
        <div class="chat-input-area">
            <input type="text" id="messageInput" placeholder="输入消息..." />
            <button class="send-button" id="sendButton">发送</button>
        </div>
    </div>
    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const chatMessages = document.getElementById('chatMessages');
            const messageInput = document.getElementById('messageInput');
            const sendButton = document.getElementById('sendButton');
            const typingIndicator = document.getElementById('typingIndicator');
            // 模拟AI回复的延迟和内容
            const aiResponses = [
                "你好!很高兴和你聊天。",
                "这是一个很有趣的话题。",
                "我明白了,你的想法很有创意。",
                "让我想想... 嗯,我认为这是一个好主意。",
                "谢谢你的分享!",
                "如果你还有其他问题,随时可以问我。",
                "今天过得怎么样?",
                "希望这个回答能帮到你。"
            ];
            // 自动滚动到底部
            function scrollToBottom() {
                chatMessages.scrollTop = chatMessages.scrollHeight;
            }
            // 创建并添加消息到对话框
            function addMessage(text, isSent = true) {
                const messageDiv = document.createElement('div');
                messageDiv.classList.add('message');
                if (isSent) {
                    messageDiv.classList.add('sent');
                } else {
                    messageDiv.classList.add('received');
                }
                const bubbleDiv = document.createElement('div');
                bubbleDiv.classList.add('bubble');
                bubbleDiv.textContent = text;
                messageDiv.appendChild(bubbleDiv);
                chatMessages.appendChild(messageDiv);
                // 添加动画后滚动到底部
                setTimeout(scrollToBottom, 10);
            }
            // 模拟AI正在输入
            function simulateTyping() {
                typingIndicator.style.display = 'flex';
                scrollToBottom();
            }
            // 模拟AI回复
            function simulateAIResponse() {
                setTimeout(() => {
                    typingIndicator.style.display = 'none';
                    const randomResponse = aiResponses[Math.floor(Math.random() * aiResponses.length)];
                    addMessage(randomResponse, false);
                }, 1500); // 模拟思考1.5秒后回复
            }
            // 发送消息的处理函数
            function handleSendMessage() {
                const messageText = messageInput.value.trim();
                if (messageText === '') return;
                // 1. 添加用户发送的消息
                addMessage(messageText, true);
                // 2. 清空输入框
                messageInput.value = '';
                // 3. 显示AI正在输入的指示器
                simulateTyping();
                // 4. 模拟AI回复
                simulateAIResponse();
            }
            // 绑定发送按钮点击事件
            sendButton.addEventListener('click', handleSendMessage);
            // 绑定输入框的回车键事件
            messageInput.addEventListener('keypress', (event) => {
                if (event.key === 'Enter') {
                    handleSendMessage();
                }
            });
            // 模拟一条初始欢迎消息
            setTimeout(() => {
                addMessage("你好!我是你的智能助手,有什么可以帮助你的吗?", false);
            }, 500);
        });
    </script>
</body>
</html>

代码解析

HTML 结构

  • chat-container: 整个聊天界面的外层容器。
  • chat-header: 顶部标题栏,显示聊天对象信息。
  • chat-messages: 消息列表容器,使用 flex-direction: column 让消息垂直排列。
  • message: 单条消息的容器,它有两个关键类:received (接收的消息) 和 sent (发送的消息),用于控制消息的对齐方式。
  • bubble: 消息气泡本身,是消息文本的容器。
  • typing-indicator: 打字指示器,默认隐藏,当AI“思考”时显示。
  • chat-input-area: 底部输入区域,包含输入框和发送按钮。

CSS 样式

  • 布局与弹性盒子: 整个聊天界面使用 flex 布局。chat-container 是一个垂直的 flex 容器。chat-messages 使用 flex: 1 自动占据所有可用空间,chat-input-area 固定在底部。
  • 消息对齐: 通过 align-self: flex-startalign-self: flex-end 分别控制接收和发送消息的对齐方式,发送的消息还使用了 flex-direction: row-reverse 将内部的头像和气泡顺序反转,实现“气泡在右”的效果。
  • 动画效果:
    • 消息淡入: 新消息通过 opacity: 0transform: translateY(20px) 初始设置为不可见并向下偏移,然后使用 @keyframes fadeInUp 动画,在 3s 内将其变为可见并回到原位。animation: fadeInUp 0.3s ease forwards 中的 forwards 关键字确保动画结束后保持在最终状态。
    • 打字指示器: 三个小圆点通过 @keyframes typing 动画,以不同的延迟时间上下跳动,模拟打字效果。

JavaScript 逻辑

  • DOM 元素获取: 通过 document.getElementById 获取所有需要操作的DOM元素。
  • scrollToBottom() 函数: 一个简单的辅助函数,用于在每次新消息或打字指示器出现时,将聊天区域的滚动条自动拉到最底部。
  • addMessage(text, isSent) 函数:
    • 动态创建 messagebubble DOM 元素。
    • 根据 isSent 参数添加 receivedsent 类,以区分消息样式。
    • 将创建好的消息添加到 chatMessages 容器中。
    • 使用 setTimeout 确保 DOM 更新后,再调用 scrollToBottom,实现平滑滚动。
  • simulateTyping()simulateAIResponse() 函数:
    • 这两个函数是模拟AI交互的核心。
    • simulateTyping() 显示打字指示器并滚动。
    • simulateAIResponse()setTimeout 中执行,模拟AI的“思考时间”(1.5秒),时间到后,隐藏指示器,并从预设的回复列表中随机选择一条,调用 addMessage 添加到界面。
  • 事件监听:
    • 为发送按钮和输入框绑定了 clickkeypress 事件。
    • keypress 事件中判断 event.key === 'Enter',实现了按回车键发送消息的功能。
  • 初始消息: 页面加载后,通过 setTimeout 模拟AI发送一条欢迎消息,增加真实感。

这个特效结合了现代前端开发的多种技术,可以作为一个很好的基础,进一步扩展为功能更完整的聊天应用。