一、基本结构
<template>
<div class="chat-room">
<div class="chat-history">
<div v-for="message in messages" class="chat-message" :class="{ 'my-message': message.isMyMessage }">
<div class="message-details">
<p class="username">{{ message.username }}</p>
<p class="time">{{ message.time }}</p>
</div>
<p class="message-body">{{ message.body }}</p>
</div>
</div>
<div class="chat-input">
<input type="text" placeholder="Type a message" v-model="newMessage" @keyup.enter="sendMessage">
<button class="send-message-btn" @click="sendMessage">发送</button>
</div>
</div>
</template>
以上是一个简单的聊天对话框组件的基本结构,其中包括两部分:chat-history和chat-input。chat-history是展示聊天记录的部分,chat-input是用户输入聊天内容的部分。
在组件内部,我们需要定义一个序列,用来保存聊天记录信息,即messages。messages数组中的每一项应该包含三个属性:username、time和body。当用户发送聊天信息时,我们应该在input框中以v-model的形式绑定到一个叫做newMessage的数据上,同时通过keyup.enter事件监听用户回车输入,并执行sendMessage方法。
以下是组件内data以及sendMessage方法的基本结构:
<script>
export default {
data() {
return {
messages: [], // 聊天记录序列
newMessage: '' // 用户输入的聊天信息
}
},
methods: {
sendMessage() {
// 创建消息对象
let newMsg = {
username: '某某用户',
time: new Date().toLocaleString(), // 获取当前时间并格式化
body: this.newMessage,
isMyMessage: true // 标记为本人发出的信息
};
// 将消息添加到消息序列中去
this.messages.push(newMsg);
// 将input框的值清空
this.newMessage = '';
// 滚动到最底部
this.$nextTick(() => {
this.$refs.chatHistory.scrollTop = parseInt(window.getComputedStyle(this.$refs.chatHistory).height);
});
}
}
};
</script>
在sendMessage方法中,我们在将用户发送的聊天记录push到messages序列中之后,还需要执行输入框清空、机器回复、窗口滑动到最下方的任务。
二、样式美化
.chat-room {
display: flex;
flex-direction: column;
justify-content: flex-end;
height: 400px;
width: 400px;
border: 5px solid #C1C1C1;
border-radius: 5px;
box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.2);
overflow: hidden;
}
.chat-history {
flex: 1;
padding: 20px 20px 0;
margin-bottom: 10px;
overflow-y: scroll;
word-break: break-all; /* 长文本断行 */
}
.chat-message {
display: flex;
}
.message-details {
margin-right: 10px;
font-size: 14px;
color: #999;
}
.my-message .message-details {
margin-left: 10px;
margin-right: 0;
text-align: right;
}
.message-body {
background-color: #EEE;
padding: 10px 15px;
border-radius: 10px;
max-width: 75%;
}
.my-message .message-body {
background-color: #4CAF50;
color: white;
margin-right: 10px;
}
.chat-input {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #C1C1C1;
padding: 10px 20px;
}
.chat-input input[type="text"] {
border: none;
outline: none;
font-size: 14px;
padding: 8px;
flex: 1;
margin-right: 10px;
background-color: #F0F0F0;
border-radius: 3px;
::placeholder {
color: #AAA;
}
}
.chat-input .send-message-btn {
border: none;
outline: none;
background-color: #008CBA;
color: white;
padding: 8px;
border-radius: 3px;
cursor: pointer;
transition: all ease-in-out 0.2s;
&:hover {
background-color: #005F6B;
}
}
除了基本的布局之外,我们还需要通过CSS样式来进行美化,让聊天对话框看起来更具有交互性。
样式段落中定义了对话框的基本样式以及聊天记录、用户发送内容的美化样式。需要注意的是,为了更好的用户体验,我们需要将聊天记录容器chat-history设置为自动滚动,确保用户一直能看到最新的消息内容,同时也避免了消息被屏幕遮盖的问题。
三、小技巧
1、消息的自动滚动
this.$nextTick(() => {
this.$refs.chatHistory.scrollTop = parseInt(window.getComputedStyle(this.$refs.chatHistory).height);
});
在sendMessage方法中,我们需要将窗口滚动到最底部,以便用户能够看到最新的聊天记录。由于Vue动态渲染的特殊性,直接使用原生JS获取元素height值来进行scrollTop的赋值是行不通的,因为在代码尚未渲染完成时,我们得到的height是初始值0。所以我们需要以异步代码的形式,通过Vue的$nextTick方法帮助我们等待元素渲染完成后再进行scroll操作,以获取正确的height值。
2、机器人自动回复
sendMessage() {
// ...
// 机器人自动回复
setTimeout(() => {
let replyMsg = {
username: '机器人小随',
time: new Date().toLocaleString(),
body: '您的消息已收到,稍后将有专人为您服务。',
isMyMessage: false
};
this.messages.push(replyMsg);
this.$nextTick(() => {
this.$refs.chatHistory.scrollTop = parseInt(window.getComputedStyle(this.$refs.chatHistory).height);
});
}, 1000);
}
在用户发送内容之后,我们通常需要在服务器、数据库等后端系统处进行处理。但是在前端展示时,我们可以通过异步代码来使机器人自动回复用户的消息。在sendMessage方法中,我们需要使用setTimeout进行延时操作,并创建一个replyMsg对象,模拟机器人的回复消息,然后将其push到messages序列中。最后,我们再次执行窗口滑动到最下方的操作,确保用户能够看到机器人回复的内容。
3、监听滚动事件
mounted() {
this.$refs.chatHistory.addEventListener('scroll', this.handleScroll)
},
destroyed() {
this.$refs.chatHistory.removeEventListener('scroll', this.handleScroll)
},
methods: {
handleScroll() {
let scrollTop = this.$refs.chatHistory.scrollTop;
if (scrollTop === 0) {
// 执行加载更多的操作
}
}
}
在一些场景下,我们可能需要用户滚动到聊天记录的顶部时,自动加载更多的历史聊天记录。Vue提供了一种事件监听的方式,让我们可以轻松地实现该功能。在聊天对话框被挂载到DOM之后,我们可以通过addEventListener监听chatHistory元素的scroll事件。当scroll事件被触发时,我们可以通过判断scrollTop的大小来判断用户是否滑动到了顶部。如果scrollTop为0,代表用户已经滑动到顶部了,此时可以执行加载更多的操作。需要注意,Vue中,在组件销毁时需要在destroyed生命周期中移除scroll事件的监听。
4、处理超长聊天记录的断行
.chat-history {
// ...
word-break: break-all;
}
在用户发送的聊天记录中,如果有长时间的文本、链接等内容,我们需要进行处理,以保证UI的美观性和阅读性。在样式段落中,我们使用CSS的word-break属性进行处理:当聊天记录的文本元素宽度超过父元素宽度时,自动断行,并将一些单词或连接符号拆分到下一行。这样能够有效解决聊天记录文本溢出、遮盖的问题,提高聊天室的可用性。