571
社区成员
发帖
与我相关
我的任务
分享随着互联网的日益普及和人们沟通交流需求日益旺盛,聊天室逐渐成为人们最喜爱的软件之一,该项目基于学习的目的,实现一个基于vue和websocket的简易聊天室。
Vue.js是一个用于创建用户界面的开源Model–view–viewmodel前端JavaScript框架,也是一个基于双向绑定的创建单页应用的组件化Web应用框架。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。MVVM具有低耦合、可重用性、独立开发等优点。

WebSocket是一种网络传输协议,可在单个TCP连接上进行全双工通信,位于OSI模型的应用层。它使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

选择在线用户,进行1v1聊天

创建房间,进行多人聊天
选择已存在房间,加入聊天

服务端主要代码:
var server = ws.createServer(function(conn){
conn.on("text", function (obj) {
obj = JSON.parse(obj);
conns[''+obj.uid+''] = conn;
switch(obj.type){
// 创建连接
case 1:
let isuser = users.some(item=>{
return item.uid === obj.uid
})
if(!isuser){
users.push({
nickname: obj.nickname,
uid: obj.uid,
status: 1
});
} else {
users.map((item, index)=>{
if(item.uid === obj.uid){
item.status = 1;
}
return item;
})
}
boardcast({
type: 1,
date: moment().format('YYYY-MM-DD HH:mm:ss'),
msg: obj.nickname+'加入聊天室',
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge
});
break;
// 注销
case 2:
// delete conns[''+obj.uid+''];
users.map((item, index)=>{
if(item.uid === obj.uid){
item.status = 0;
}
return item;
})
boardcast({
type: 1,
date: moment().format('YYYY-MM-DD HH:mm:ss'),
msg: obj.nickname+'退出了聊天室',
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: []
});
break;
// 创建房间
case 10:
groups.push({
id: moment().valueOf(),
name: obj.groupName,
users: [{
uid: obj.uid,
nickname: obj.nickname
}]
})
boardcast({
type: 1,
date: moment().format('YYYY-MM-DD HH:mm:ss'),
msg: obj.nickname+'创建了房间 ' + obj.groupName,
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge
});
break;
// 加入房间
case 20:
let group = groups.filter(item=>{
return item.id === obj.groupId
})[0]
group.users.push({
uid: obj.uid,
nickname: obj.nickname
})
boardcast({
type: 1,
date: moment().format('YYYY-MM-DD HH:mm:ss'),
msg: obj.nickname+'加入了房间 ' + obj.groupName,
users: users,
groups: groups,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge
});
break;
// 发送消息
default:
boardcast({
type: 2,
date: moment().format('YYYY-MM-DD HH:mm:ss'),
msg: obj.msg,
uid: obj.uid,
nickname: obj.nickname,
bridge: obj.bridge,
groupId: obj.groupId,
status: 1
});
break;
}
})
conn.on("close", function (code, reason) {
console.log("Connection closed.");
});
conn.on("error", function (code, reason) {
console.log("Connection error.");
});
}).listen(80)
前端主要代码:
<div id="app">
<c-dialog ref="loginDialog" title='请输入你的昵称' confirmBtn="开始聊天" @confirm="login">
<input class="nickname" v-model="nickname" type="text" placeholder="请输入你的昵称">
</c-dialog>
<c-dialog ref="createGroupDialog" title='请输入房间名称' confirmBtn="确认" @confirm="createGroup">
<input class="nickname" v-model="groupName" type="text" placeholder="请输入房间名称">
</c-dialog>
<div class="web-im dis-flex">
<div class="left">
<div class="aside content">
<div class="header">
<div class="tabbar dis-flex">
<label :class="{active:switchType==1, unread: usersUnRead}" for="" @click="switchType=1">在线人员</label>
<label :class="{active:switchType==2, unread: groupsUnRead}" for="" @click="switchType=2">房间</label>
</div>
</div>
<div class="body user-list">
<div>
<div v-if="switchType==2" class="user" @click="triggerGroup(item)" v-for="(item,index) in currentGroups" :key="index">
{{item.name}}
<span class="tips-num" v-if="item.unread">{{item.unread}}</span>
<span v-if="!checkUserIsGroup(item)" @click.stop="addGroup(item)" class="add-group">+</span>
</div>
</div>
<div >
<div v-if="switchType==1 && item.uid!=uid" class="user" @click="triggerPersonal(item)" :class="{offline: !item.status}" v-for="(item,index) in currentUserList" :key="index">
{{item.nickname}}
<span class="tips-num" v-if="item.unread">{{item.unread}}</span>
</div>
</div>
</div>
<div class="footer">
<div class="func dis-flex">
<label @click="$refs.createGroupDialog.show()">创建房间</label>
</div>
</div>
</div>
</div>
<div class="right content">
<div class="header im-title">{{title}}</div>
<div class="body im-record" id="im-record">
<div class="ul">
<div class="li" :class="{user: item.uid == uid}" v-for="(item,index) in currentMessage" :key="index">
<template v-if="item.type===1">
<p class="join-tips">{{item.msg}}</p>
</template>
<template v-else>
<p class="message-date">
<span class="m-nickname">{{item.nickname}}</span> {{item.date}}</p>
<p class="message-box" >{{item.msg}}</p>
</template>
</div>
</div>
</div>
<div class="footer im-input dis-flex">
<input type="text" v-model="msg" placeholder="请输入内容">
<button @click="send">发送</button>
</div>
</div>
</div>
</div>
作者:NP283