- 气泡动画:消息从发送者头像位置“飞入”对话框。
- 打字指示器:模拟对方正在输入的动画效果。
- 流畅的滚动:新消息出现时,对话框自动滚动到底部。
- 现代化设计:采用了类似微信或 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-start和align-self: flex-end分别控制接收和发送消息的对齐方式,发送的消息还使用了flex-direction: row-reverse将内部的头像和气泡顺序反转,实现“气泡在右”的效果。 - 动画效果:
- 消息淡入: 新消息通过
opacity: 0和transform: translateY(20px)初始设置为不可见并向下偏移,然后使用@keyframes fadeInUp动画,在3s内将其变为可见并回到原位。animation: fadeInUp 0.3s ease forwards中的forwards关键字确保动画结束后保持在最终状态。 - 打字指示器: 三个小圆点通过
@keyframes typing动画,以不同的延迟时间上下跳动,模拟打字效果。
- 消息淡入: 新消息通过
JavaScript 逻辑
- DOM 元素获取: 通过
document.getElementById获取所有需要操作的DOM元素。 scrollToBottom()函数: 一个简单的辅助函数,用于在每次新消息或打字指示器出现时,将聊天区域的滚动条自动拉到最底部。addMessage(text, isSent)函数:- 动态创建
message和bubbleDOM 元素。 - 根据
isSent参数添加received或sent类,以区分消息样式。 - 将创建好的消息添加到
chatMessages容器中。 - 使用
setTimeout确保 DOM 更新后,再调用scrollToBottom,实现平滑滚动。
- 动态创建
simulateTyping()和simulateAIResponse()函数:- 这两个函数是模拟AI交互的核心。
simulateTyping()显示打字指示器并滚动。simulateAIResponse()在setTimeout中执行,模拟AI的“思考时间”(1.5秒),时间到后,隐藏指示器,并从预设的回复列表中随机选择一条,调用addMessage添加到界面。
- 事件监听:
- 为发送按钮和输入框绑定了
click和keypress事件。 keypress事件中判断event.key === 'Enter',实现了按回车键发送消息的功能。
- 为发送按钮和输入框绑定了
- 初始消息: 页面加载后,通过
setTimeout模拟AI发送一条欢迎消息,增加真实感。
这个特效结合了现代前端开发的多种技术,可以作为一个很好的基础,进一步扩展为功能更完整的聊天应用。
