聊天室的实现核心在于 WebSocket 协议。通过为双方建立全双工通信,使得用户端可以随时接收来自服务端的数据。
WebSocket 如图:
聊天信息渲染为数组
以数组的形式存储聊天数据,并在页面中使用 v-for
进行遍历循环:
<tempalte>
<!-- 聊天区域 -->
<div class="chat">
<div class="item" v-for="(item, index) in chatList" :key="index">
<van-image class="img" :class="{ right: item.isme }" round src="xx.xx"></van-image>
<div class="con" :class="{ right: item.isme }"> {{ item.t }} </div>
</div>
</div>
</tempalte>
<script>
export default {
data() {
return {
// 输入框中的内容
msg: "",
// 聊天的数组
chatList: [
{ isme: false, t: "你好啊!" },
{ isme: true, t: "你好!" },
],
};
},
}
</script>
实时滚动到底部
每次发送信息之后,需要及时滚动到底部以展示发送的信息。
submit() {
// 点击之后将输入框中的内容添加到 chatList 中
if (this.msg) {
this.chatList.push({
isme: true,
t: this.msg,
});
this.msg = "";
this.$nextTick(() => {
// 滚动到最后面
this.$refs.chat.scrollTop = this.$refs.chat.scrollHeight;
});
}
},
使用 socket.io 库完成聊天功能
WebSocket 提供了 socket.io
的 JavaScript 库,它简化并兼容了 WebSocket 协议的编码实现。
- 下载第三方包:
# 下载socket.io 客户端版本,我们的项目只用的上客户端(建议版本)
npm i socket.io-client
# 下载socket.io 全套(包括端服务端用的和客户端用的)(不建议)
npm i socket.io
-
建立服务器的连接
let socket = io('http://toutiao.itheima.net', { query: { token: 用户token }, transports: ['websocket'] })
-
收消息
socket.on('message', function (data) {})
-
发消息
socket.emit('message', { msg: '消息内容', timestamp: '发送消息的时间戳' })
实现
<template>
<div class="zhi">
<!-- 聊天区域 -->
<div class="chat" ref="chatList">
<div class="item" v-for="(item, index) in chatList" :key="index">
<van-image class="img" :class="{ right: item.isme }" round src="xx.xx"></van-image>
<div class="con" :class="{ right: item.isme }">
{{ item.t }}
</div>
</div>
</div>
<!-- 输入框区域 -->
<van-search class="input" v-model="msg" show-action left-icon="" placeholder="说点什么" @search="submit">
<template #action>
<div @click="submit">提交</div>
</template>
</van-search>
</div>
</template>
<script>
import io from 'socket.io-client';
export default {
name: 'Custom',
data() {
return {
// 输入框中的内容
msg: "",
he: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.jj20.com%2Fup%2Fallimg%2Fmn02%2F022420152S4%2F200224152S4-5.jpg&refer=http%3A%2F%2Fpic.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1641711357&t=432633c617c691b75441a765c2729f61',
me: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.jj20.com%2Fup%2Fallimg%2Fmn02%2F022420152S4%2F200224152S4-5.jpg&refer=http%3A%2F%2Fpic.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1641711357&t=432633c617c691b75441a765c2729f61',
chatList: [
// isme:当前对话是属于小智还是我(小智:false, 我:true)
// t:聊天的内容
{ isme: false, t: '你好啊!' },
],
socket: null
};
},
methods: {
// 1.0 点击右侧的提交按钮时会触发
// 2.0 在输入框中点击回车按钮会触发
submit() {
// 点击之后将输入框中的内容添加到 chatList 中
if (this.msg) {
// 将消息发送到服务器
this.socket.emit("message", {
msg: this.msg,
timestamp: Date.now(),
});
this.chatList.push({
isme: true,
t: this.msg,
});
this.msg = "";
this.$nextTick(() => {
// 滚动到最后面
this.$refs.chatList.scrollTop = this.$refs.chatList.scrollHeight;
});
}
},
},
created() {
//建立连接
this.socket = io('http://toutiao.itheima.net', {
query: {
token: 'dwjidwjio'
},
transports: ['websocket']
});
//监听服务器
this.socket.on("message", (data) => {
console.log(data);
// 将内容添加到聊天列表中
this.chatList.push({
isme: false,
t: data.msg,
});
// 自动滚动到底部
this.$nextTick(() => {
// 滚动到最后面
this.$refs.chatList.scrollTop = this.$refs.chatList.scrollHeight;
});
});
}
};
</script>
<style lang="scss">
.zhi {
font-size: 16px;
.chat {
position: fixed;
top: 46px;
bottom: 54px;
left: 0px;
right: 0px;
background-color: #eee;
overflow: auto;
.item {
overflow: hidden;
margin: 10px;
.img {
float: left;
width: 40px;
height: 40px;
margin-right: 10px;
&.right {
float: right;
margin-right: 0px;
margin-left: 10px;
}
}
.con {
float: left;
border: 1px solid #3196fa;
max-width: 70%;
padding: 10px;
background-color: #e0effb;
&.right {
float: right;
border: 1px solid #c5e2d4;
background-color: #9eea6a;
}
}
}
}
.input {
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
padding: 10px;
}
}
</style>