您的位置:

Vue聊天对话框详解

一、基本结构


<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属性进行处理:当聊天记录的文本元素宽度超过父元素宽度时,自动断行,并将一些单词或连接符号拆分到下一行。这样能够有效解决聊天记录文本溢出、遮盖的问题,提高聊天室的可用性。