最近剛寫了一個線上群聊的功能。
一個是vue頁面;
一個是背景服務js;需要先下載下傳ws
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<style>
.after {
display: flex;
}
.after .left .content {
width: 500px;
height: 300px;
border: solid 1px red;
overflow: scroll;
overflow-x: hidden;
padding: 0 20px;
}
.after .left .content .notice {
text-align: center;
}
.after .left .content .myMessage {
text-align: right;
}
.after .left .content .message {
border: solid 2px black;
display: inline-block;
}
.after .right {
width: 200px;
height: inherit;
border: solid 1px blue;
}
.after .right .isMe {
color: red;
}
</style>
</head>
<body>
<div id="app">
<!-- 先輸入昵稱 -->
<div class="before" v-if="!ifEnter">
<input v-model="userName" :value="userName" search enter-button="确定"
placeholder="請輸入您的昵稱" />
<button @click="settingName">确定</button>
</div>
<!-- 開始群聊 -->
<div class="after" v-else>
<div class="left">
<!-- 聊天内容 -->
<div class="content" id="content">
<div v-for="(item,index) in messageList" :key="index">
<!-- 加入群聊 -->
<div class="notice" v-if="item.type=='addUser'">
<h2>{{item.user}}加入群聊</h2>
</div>
<!-- 退出群聊 -->
<div class="notice" v-if="item.type=='quit'">
<div>{{item.user}}退出群聊</div>
</div>
<!-- 收到消息 -->
<div :class="{'myMessage':item.userId==userId}" v-if="item.type=='message'">
<div>{{item.user}}:{{item.time}}</div>
<h3 class="message">{{item.content}}</h3>
</div>
</div>
</div>
<!-- 編輯欄 -->
<div>
<input v-model="text" style="width: 200px;" />
<button type="info" @click="send()">發送</button>
<button type="error" @click="quit()">退出</button>
</div>
</div>
<!-- 使用者資訊 -->
<div class="right">
<h1>《使用者清單》</h1>
<div v-for="(item,index) in users" :key="index" :class="{'isMe':item.userId==userId}">{{item.userName}}(
{{item.userId}} )</div>
</div>
</div>
</div>
</body>
<script>
new Vue({
el:'#app',
data:{
messageList: [], //所有消息清單
users: [], //使用者清單
ifEnter: false, //是否聊天狀态
userName: '遊客',
userId: '',
text: '大家好 丫~我是婷婷兒', //内容
ws: null, //wbs
message: { //發送的消息格式
type: '', //發送類型
user: '',
userId: '',
toUser: '', //消息接收方名
toUser: '', //消息接收方id
content: '', //發送内容
time: '' //發送時間
}
},
methods: {
// 退出聊天室
quit() {
this.message.type = 'quit';
this.message.content = this.text;
this.ws.onopen();
this.ws.close();
this.ifEnter = false;
},
// 設定昵稱
settingName() {
this.ifEnter = true;
this.userId = new Date().getTime();
this.message.type = 'addUser';
this.message.user = this.userName;
this.message.userId = this.userId;
this.message.time = new Date().toLocaleString()
this.initWbs();
},
// wbs初始化;
initWbs() {
this.ws = new WebSocket(`ws://localhost:8080/chat?userId=${this.message.userId}&userName=${this.userName}`);
// 設定屬性
// 連接配接時
this.ws.onopen = (e) => {
var sendMessage = JSON.stringify(this.message);
this.ws.send(sendMessage)
};
// 收到資訊時
this.ws.onmessage = (e) => {
var recieve = JSON.parse(e.data);
switch (recieve.type) {
// 首次連接配接會發送所有使用者資訊
case 'allUser':
this.users = recieve.userList;
break;
// 添加使用者
case 'addUser':
break;
// 退出消息
case 'quit':
// 獲得退出使用者資訊,從清單中去掉;
this.users = this.users.filter((element, index) => {
if (recieve.userId != element.userId) {
return element;
}
})
break;
// 普通消息
}
if (recieve.type != 'allUser') {
this.messageList.push(recieve);
// ue中資料和dom渲染由于是異步的,是以,要讓dom結構随資料改變這樣的操作都應該放進this.$nextTick()的回調函數中。
this.$nextTick(() => {
var ele = document.getElementById('content');
ele.scrollTop = ele.scrollHeight - ele.clientHeight;
})
}
};
// 退出時
this.ws.onclose = () => {
this.users = [];
console.log(this.users)
this.messageList = [];
console.log("你已經退出聊天室了!!");
};
},
send() {
this.message.type = 'message';
this.message.content = this.text;
this.ws.onopen();
}
}
})
</script>
</html>
var WebSocket = require('ws');
var wsList = [];//連接配接使用者清單
var usersInfo = {
type: 'allUser',
userList: []
};
const wss = new WebSocket.Server({ port: 8080 });
function wbs() {
wss.on('connection', function connection(ws, req) {
// 第一次連接配接消息時
connectNow(ws, req)
// 接受消息時
ws.on('message', function incoming(data) {
// 根據發送的data分類
message(ws, data);
});
});
}
// 發現使用者退出群以後,從清單上去掉,再群發使用者資訊;
function message(ws, data) {
var getDate = JSON.parse(data);
switch (getDate.type) {
// 使用者退出
case 'quit':
var nowUserList = usersInfo.userList.filter(element => {
if (element.userId != getDate.userId) {
return element;
}
})
usersInfo.userList = nowUserList;//更新使用者清單
// 群發退出的使用者資訊
wsList.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
break;
case 'addUser':
// 增加使用者
wsList.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
break;
case 'message':
// 普通消息群發
wsList.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
break;
}
}
// 第一次連接配接以後伺服器給前端發送消息
function connectNow(ws, req) {
var info = getParams(req.url);
ws.info = info;
wsList.push(ws);
usersInfo.userList.push(info)
wsList.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(usersInfo));
}
});
}
// 解析參數
function getParams(url) {
var params = url.split('?')[1].split('&');
var paramsList = {};
params.forEach(element => {
var info = element.split('=');
if (info[0]) {
paramsList[decodeURIComponent(info[0])] = decodeURIComponent(info[1])
}
})
return paramsList;
}
module.exports = wbs;