基于vue+vue-socket.io +express + mongodb + elementUi定义自己的聊天工具

先上成品图片


chat.PNG

技术应用以及功能介绍

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,387评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,845评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,091评论 0 246
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,308评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,662评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,795评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,008评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,466评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,687评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,181评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,531评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,177评论 3 239
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,126评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,862评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,734评论 2 274

推荐阅读更多精彩内容

  • 金秋九月,艳阳高照; 秋风微微,波光粼粼。 彩旗飘飘,锣鼓喧天; 舞龙弄狮,助喊呐威。 河水两岸,人群攒动; 壮士...
    五柳亦阅读 205评论 0 1
  • 首因效应由美国心理学家洛钦斯首先提出的,也叫首次效应、优先效应或第一印象效应,指交往双方形成的第一次印象对今后交往...
    天涯若有邻阅读 2,787评论 0 1
  • 今天我们来谈谈火箭少女的新歌《Light》。 这首歌不知道为什么,十分触动吧。像是写了我的青春,初...
    木华十桦阅读 385评论 0 0
  • 阅读启智 伴我成长 稚嫩的声音在我们的小口中发出,一阵阵郎朗的读书声,响彻在教室内、课堂外、家庭中....
    史文才阅读 654评论 0 0