先上成品图片
技术应用以及功能介绍
1.前端框架时用vue2搭建,基于elementUI
2.vue-socket.io长连接的使用
3.用户登陆退出的实时显示
4.聊天数据的保存
3.后端使用express + mongoose来对数据进行操作,主要包括增删改查等
上面技术的使用之前的文章有写,包括vue+express的使用以及mongoose数据库的连接https://www.jianshu.com/p/f50aa818ab66:vue+express的使用
https://www.jianshu.com/p/440bb0c9d7f8 :mongoose数据库的连接
下面介绍vue-socket.io长连接的使用
1.安装
cnpm i vue-socket.io --save
//这里安装使用可能会报错,如果报错使用vue-socket.io的`^2.1.1-a`版本安装
2.在main.js引入
import VueSocketio from 'vue-socket.io';
Vue.use(VueSocketio,'http://localhost:3000/');
//后面的连接为后端地址,这里express启动的地址端口默认时3000
3.在server/bin/www也就是express目录文件夹下加入以下代码:
var io = require('socket.io').listen(server.listen(port));
4.定义用户表结构:models文件夹下定义chat.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var chatObj = new Schema({
groupPepole: String,
groupTime: String
});
module.exports = mongoose.model('chats',chatObj);
// chatName: String,
// chatTime: String
5.定义内容表结构在:models文件夹下定义chatcontent.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var chatconObj = new Schema({
chatName: String,
chatTime: String,
chatContent: String
});
module.exports = mongoose.model('chatcontents',chatconObj);
6.基于experss的增删改查如下:在routers下定义chat.js,并在app.js下引入
var chatRouter = require('./routes/chat');
app.use('/chat', chatRouter);
chat.js代码如下:
var express = require('express');
var Router = express.Router();
var chatModel = require('../models/chat');
var chatConModel = require('../models/chatcontent');
// 保存登陆用户
Router.post('/pepole',function(req,res,next){
let newDate = new Date();
let pepoleList = new chatModel({
groupPepole: req.body.loginName,
groupTime: newDate.toLocaleDateString() + ' ' + newDate.toLocaleTimeString()
});
pepoleList.save(function(err,doc){
if(err) {
res.json({
states: 0,
msg: err.message
});
}else {
res.json({
states: 1,
msg: '保存成功'
});
}
});
// 保存用户发布内容
Router.post('/content',function(req,res,next){
let newDate = new Date();
let conList = new chatConModel({
chatName: req.body.chatName,
chatContent: req.body.chatContent,
chatTime: newDate.toLocaleDateString() + ' ' + newDate.toLocaleTimeString()
});
conList.save(function(err,doc){
if(err) {
res.json({
states: 0,
msg: err.message
});
}else {
res.json({
states: 1,
msg: '保存成功'
});
}
});
});
//获取内容并返回
Router.post('/geContentList',function(req,res,next){
chatConModel.find({}, function(err,doc){
if(err) {
res.json({
states: 0,
msg: err.message
});
}else {
res.json({
states: 1,
msg: doc,
count:doc.length
});
}
});
});
//获取用户列表
Router.post('/getUserList',function(req,res,next){
chatModel.find({}, function(err,doc){
if(err) {
res.json({
states: 0,
msg: err.message
});
}else {
res.json({
states: 1,
msg: doc,
count:doc.length
});
}
});
});
//退出登陆
Router.post('/out',function(req,res,next){
let conditions = {
groupPepole: req.body.loginName
}
chatModel.remove(conditions, function (err,doc) {
if(err) {
res.json({
states: 0,
msg: err.message
});
}else {
res.json({
states: 1,
msg: 'doc'
});
}
});
});
module.exports = Router;
下面时长连接的使用
1.在server/bin/www下加入以下代码:
io.sockets.on('connection', (socket) => {
console.log('链接成功了呀');
//监听新用户加入
socket.on('login', function(obj){
//向所有客户端广播用户加入
io.emit('login', obj);
// console.log(obj.username+'加入了聊天室');
});
socket.on('out', function(obj){
//向所有客户端广播用户加入
io.emit('out', obj);
// console.log(obj.username+'加入了聊天室');
});
socket.on('content', function(obj){
//向所有客户端广播用户加入
io.emit('content', obj);
// console.log(obj.username+'加入了聊天室');
});
});
在前端使用如下:
// 长连接
sockets: {
//不能改,j建立连接自动调用connect
connect: function() {
//与socket.io连接后回调
console.log("socket connected");
},
//服务端向客户端发送login事件
login: function(value) {
//监听login(后端向前端emit login的回调)
this.userList.push(value);
console.log(value, 'valuevaluevaluevaluevaluevalue')
},
out: function(value) {
//监听out(后端向前端emit out的回调)
this.userList.push(value);
console.log(value, 'valuevaluevaluevaluevaluevalue')
},
content: function(value) {
//监听out(后端向前端emit out的回调)
this.contentList.push(value);
console.log(value, 'valuevaluevaluevaluevaluevalue')
}
},
前端具体页面如下
<template>
<div>
<div id="chat" style="position: relative;">
<div style="position:fixed;right:100px;top:20px">
<p>当前用户:{{itemName}}</p>
<el-button type="danger" style="margin-top:20px" @click="chatLoginOut">退出</el-button>
</div>
<div style="position:fixed;top:20px;left:20px">
<el-input v-model="inputUser" placeholder="请输入用户名"></el-input>
<el-button type="primary" style="margin-top:20px" @click="chatLogin">登陆</el-button>
<p style="margin-top:10px;font-size:14px">在线人数:<span style="color:red">{{userListNew.length}}</span>人</p>
<p style="margin-top:10px;font-size:14px" v-for="(item,i) in userList" :key="i">
<span style="color:red">{{item.groupPepole}}</span>
<span v-if="item.type==='in'">上线了</span>
<span v-if="item.type==='out'">下线了</span>
<span style="padding-left:10px;color:blue;font-size:12px">{{item.groupTime}}</span>
</p>
<p></p>
</div>
<div class="sidebar">
<div class="m-card">
<header>
<img class="avatar" width="40" height="40" alt="Coffce" src="/static/img/1.jpg">
<p class="name">群名称</p>
</header>
<footer>
<input class="search" placeholder="search user...">
</footer>
</div>
<!--v-component-->
<div class="m-list">
<ul>
<!--v-for-start-->
<!-- <li>
<img class="avatar" width="30" height="30" alt="示例介绍" src="/static/img/2.png">
<p class="name">示例介绍</p>
</li> -->
<li @click="changeName(item.groupPepole)" :class="itemName===item.groupPepole ? 'active' : ''" v-for="(item,i) in userListNew" :key="i">
{{item.groupPepole}}
<!-- <img class="avatar" width="30" height="30" alt="webpack" src="/static/img/3.jpg"> -->
<!-- <p class="name">{{item.groupPepole}}</p> -->
</li>
<!--v-for-end-->
</ul>
</div>
<!--v-component-->
</div>
<div class="main">
<div class="m-message">
<ul>
<!--v-for-start--><!--v-for-end-->
<li style="height:40px" v-for="(item,i) in contentList" :key="i">
<span v-if="item.chatName!==itemName" class="contentLeft">{{item.chatName}} : {{item.chatContent}}</span>
<span v-if="item.chatName===itemName" class="contentRight">{{item.chatContent}} : {{item.chatName}}</span>
</li>
<!-- <li style="text-alain:right">121212:23232</li>
<li>121212:232323</li> -->
</ul>
</div>
<!--v-component-->
<div class="m-text">
<textarea v-model="texts" placeholder="点击按钮发送"></textarea>
<el-button type="primary" style="margin-top:20px;position: absolute;bottom: 0px;right: 0;" @click="send">发送</el-button>
</div>
<!--v-component-->
</div>
</div>
</div>
</template>
<style scoped>
.contentRight{
display: inline-block;
padding: 8px;
width: auto;
background: white;
position: absolute;
right: 20px;
}
.contentLeft{
display: inline-block;
padding: 8px;
width: auto;
background: white;
}
#chat {
overflow: hidden;
border-radius: 3px;
}
#chat {
margin: 20px auto;
width: 800px;
height: 600px;
}
#chat .sidebar {
float: left;
width: 200px;
color: #f4f4f4;
background-color: #2e3238;
}
.m-card {
padding: 9pt;
border-bottom: 1px solid #24272c;
}
.m-card .avatar {
border-radius: 2px;
}
.m-card .avatar, .m-card .name {
vertical-align: middle;
}
.m-card .name {
display: inline-block;
margin: 0 0 0 15px;
font-size: 1pc;
}
.m-card footer {
margin-top: 10px;
}
.m-card .search {
padding: 0 10px;
width: 100%;
font-size: 9pt;
color: #fff;
height: 30px;
line-height: 30px;
border: 1px solid #3a3a3a;
border-radius: 4px;
outline: 0;
background-color: #26292e;
}
.m-list li {
padding: 9pt 15px;
border-bottom: 1px solid #292c33;
cursor: pointer;
-webkit-transition: background-color .1s;
transition: background-color .1s;
position: relative;
}
.m-list .avatar {
border-radius: 2px;
}
.m-list .name {
display: inline-block;
margin: 0 0 0 15px;
position: absolute;
top: 19px;
}
.m-list li.active {
background-color: hsla(0,0%,100%,.1);
}
#chat .main {
position: relative;
overflow: hidden;
background-color: #eee;
}
#chat .m-message {
height: calc(100% - 10pc);
}
.m-message {
padding: 10px 15px;
overflow-y: scroll;
}
#chat .main, #chat .sidebar {
height: 100%;
}
#chat .m-text {
position: absolute;
width: 100%;
bottom: 0;
left: 0;
}
.m-text {
height: 10pc;
border-top: 1px solid #ddd;
}
.m-text textarea {
padding: 10px;
height: 100%;
width: 100%;
border: none;
outline: 0;
font-family: Micrsofot Yahei;
resize: none;
}
</style>
<script>
export default{
components: {
},
data(){
return{
inputUser: '',
userLoginIn: '',
userList: [],
userListNew: [],
counts: '',
itemName: '',
texts: '',
contentList: []
}
},
// 长连接
sockets: {
//不能改,j建立连接自动调用connect
connect: function() {
//与socket.io连接后回调
console.log("socket connected");
},
//服务端向客户端发送login事件
login: function(value) {
//监听login(后端向前端emit login的回调)
this.userList.push(value);
console.log(value, 'valuevaluevaluevaluevaluevalue')
},
out: function(value) {
//监听out(后端向前端emit out的回调)
this.userList.push(value);
console.log(value, 'valuevaluevaluevaluevaluevalue')
},
content: function(value) {
//监听out(后端向前端emit out的回调)
this.contentList.push(value);
console.log(value, 'valuevaluevaluevaluevaluevalue')
}
},
mounted(){
this.getUser();
this.getCon();
// this.$socket.emit('login', {username:'admin'});
},
methods: {
chatLogin() {
let newDate = new Date();
// 像后端发数据
this.$socket.emit('login', {groupPepole:this.inputUser, type: 'in'});
this.loginIn('in');
this.getUser();
},
chatLoginOut() {
let newDate = new Date();
this.$socket.emit('out', {groupPepole:this.itemName, type: 'out'});
this.loginOut();
this.getUser();
},
changeName(name) {
this.itemName = name;
},
loginIn() {
//发送请求,这里我封装了axios,报错的话可以用原生的axios请求
let paramRegist = {
type: 'post',
path: '/chat/pepole',
datas: {
loginName: this.inputUser
}
}
this.$store.dispatch(paramRegist).then(res=>{
this.$message({
message: res.data.msg,
type: 'success'
});
});
},
loginOut() {
let paramRegist = {
type: 'post',
path: '/chat/out',
datas: {
loginName: this.itemName
}
}
this.$store.dispatch(paramRegist).then(res=>{
// this.$message({
// message: res.data.msg,
// type: 'success'
// });
});
},
send() {
this.$socket.emit('content', {chatName:this.itemName, chatContent: this.texts});
let paramRegist = {
type: 'post',
path: '/chat/content',
datas: {
chatName: this.itemName,
chatContent: this.texts
}
}
this.$store.dispatch(paramRegist).then(res=>{
// this.contentList = res.data.msg;
});
},
getUser() {
let paramRegist = {
type: 'post',
path: '/chat/getUserList',
datas: {
}
}
this.$store.dispatch(paramRegist).then(res=>{
this.userListNew = res.data.msg;
this.itemName = this.userListNew[0].groupPepole
});
},
getCon() {
let paramRegist = {
type: 'post',
path: '/chat/geContentList',
datas: {
}
}
this.$store.dispatch(paramRegist).then(res=>{
this.contentList = res.data.msg;
});
}
}
}
</script>
这个就时实现简单的聊天工具,git地址如下https://github.com/a1218331130/vueBlog