基于vue2.x实现的即时通讯程序仿微信聊天6对接好友列表以及记录接口和socketIo讲授

const api = {
  GetMyFriends:'/api/myfriends'
}
  • 2、在src/api/user.js中新建api接口方法
// 获取我的好友列表
export function getMyFriends(data) {
  return request({
    url: api.GetMyFriends,
    method: 'post',
    data,
  })
}
  • 3、复制你新建的api方法名到需要引入到页面,也就是【通讯录页面】,通过import导入
import { getMyFriends } from '@/api/user'
  • 4、然后在methods方法函数内,新建获取好友列表的自定义方法,在该方法内调用getMyFriends接口方法
methods:{
   async getMyFriendsFun() {
      try {
        const res = await getMyFriends()
        console.log(res)
        this.list = res.data //注意:【list】要在data内预定义成空数组,即 list:[]
      } catch (error) {
        console.log(error)
      }
    }
}
  • 注意:【list】要在data内预定义成空数组,即 list:[ ]

  • 5、然后在mounted生命周期函数内调用getMyFriendsFun方法
  mounted () {
    this.getMyFriendsFun();
  }
  • 然后就获取到数据了~
image.png
  • 6、最后for循环这个list数组,进行数据绑定就搞定了这个通讯录好友列表了
image.png

const api = {
  GetChatMsg:'/api/query/msg'
}
  • 3、打开src/api/user.js文件,新建api接口方法,注意看清楚接口的请求方式,根据接口文档来看
// 获取好友列表记录
export function getChatMsg(params) {
  return request({
    url: api.GetChatMsg,
    method: 'get',
    params,
  })
}
  • 4、然后复制接口方法名到需要引入的页面,即chatDetail页面
import { getChatMsg } from '@/api/user';
  • 5、因为这个聊天详情页面是动态路由匹配的,所以我们在上个页面跳转的时候,要传入真实的id参数
  • 6、打开通讯录页面,找到跳转方法toDetailPage,修改传入的id参数
methods:{
  toDetailPage(item) {
      this.$router.push('/chatDetail/'+item._id)
  },
}
  • 7、然后在methods方法函数内新建获取好友聊天记录的自定义方法
methods:{
  async getChatMsgFun() {
      try {
        const res = await getChatMsg({ toId: this.$route.params.id })
        console.log(res);
        this.list = res.data; //注意:【list】要在data内预定义成空数组,即 list:[]
      } catch (error) {
        console.log(err)
      }
    }
}
  • 注意:【list】要在data内预定义成空数组,即 list:[]

  • 8、然后在mounted生命周期内调用getChatMsgFun方法
mounted () {
    this.getChatMsgFun();
},
  • 然后就获取到数据了~
image.png
  • 9、下面就是要渲染该数据了,但是因为我们中间的区域是引入的外部组件,所以要先把得到的list数组数据,通过父子组件传值的形式,传递过去,子组件使用props来接收传递过去的数组
  • 在子组件身上v-bind动态绑定传值
image.png
  • 子组件内部使用props接收传递过来的list
image.png
  • 子组件data中的list没用了,就可以删除掉了!!!

image.png
  • 10、下面就是要处理下渲染出来的数据,根据实际情况渲染,目前是这个样子的
image.png
  • 先渲染右侧数据,【我是你师傅】和【悟空好绕啊】这两条消息我们现在登陆的这个唐僧的账号发出的,所以,根据接口返回数据和接口返回字段对比
image.png

image.png
  • 如果将我们当前登录账户人发送的消息渲染在右侧呢?
  • 其他send_id是发送者的id,那谁是发送者呢?当然是当前登录的账户人是发送者,那么将此send_id当前登录账户人的个人id进行对比,如果相等就是渲染在右侧的!
  • send_id有了,现在的问题是如何获取到当前登录账户人的id呢?
  • 这就需要修改下获取个人信息接口存储的数据
  • 打开src/store/modules/app.js
image.png
getUserInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getUserInfo().then(response => {
        const { data } = response
        if (!data) {
          return reject('Verification failed, please Login again.')
        }
        const { username } = data
        commit('SET_USER_NAME', data)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },
  • 这样,我们vuex中state里的userName存储的就是当前登录账户人的个人信息了,就是下图,id就在里面

image.png
  • 11、我们可以通过vuex的mapGetters来拿到上图中的对象数据
  • 先在chatDetail页面引入mapGetters
import { mapGetters } from 'vuex';
  • 在通过计算属性拿到userName对象
computed: {
    ...mapGetters(['userName'])
},
  • 12、下面就可以渲染右侧的聊天记录数据了
image.png
  • 那么右侧的数据就渲染好了,在渲染下头像send_avatar就搞定右侧了
image.png
13、下面来分析下如何渲染左侧数据
  • 首先 我们的地址栏参数,那个id就是对方的id,也就是和谁聊天的那个人的id,那么针对左侧的聊天记录来说,左侧的消息是谁发的呢?是对方发的,那么对方就是发送方,那左侧聊天信息的send_id就是发送方的id,那么既然地址栏参数,那个id就是对方的id,那地址栏的id==左侧聊天信息的send_id是不是就可以渲染左侧数据了呢
image.png
  • 搞定!!!

<template>
  <div class="chatList">
    <ul>
      <template v-for="(item,index) in list" >
      <!-- 左侧 -->
      <li v-if="$route.params.id==item.send_id" :key="index">
        <div class="left">
          <img :src="item.send_avatar" alt="">
        </div>
        <div class="right">
          <p class="time">{{item.date}}</p>
          <p class="content">
            {{item.message}}
          </p>
        </div>
      </li>
      <!-- 右侧 -->
      <li class="r" v-if="item.send_id==userName._id" :key="index">
        <div class="right">
          <p class="time">{{item.date}}</p>
          <p class="content">
            {{item.message}}
          </p>
        </div>
        <div class="left">
          <img :src="item.send_avatar" alt="">
        </div>
      </li>
    </template>
    </ul>
  </div>
</template>

<script>
import { mapGetters } from 'vuex';
export default {
  props:['list'],
  data() {
    return {
      
    }
  },
  computed: {
    ...mapGetters(['userName'])
  },
}
</script>

<style lang="scss" scoped>
.chatList{
  ul{
    padding: 20px;
    box-sizing: border-box;
    li{
      display: flex;
      margin-bottom: 40px;
      .left{
        width: 92px;
        height: 92px;
        margin-right: 16px;
        img{
          width: 100%;
          height: 100%;
          border-radius: 50%;
        }
      }
      .right{
        flex: 1;
        p{
          margin: 0;
        }
        p.time{
          font-size: 24px;
          margin-bottom: 8px;
        }
        p.content{
          font-size: 28px;
          background: #00ccb8;
          padding: 12px;
          border-radius: 12px;
          color:#fff;
          display: inline-block;
        }
      }
    }
    li.r{
      p.time{
        text-align: right;
      }
      p.content{
        background: #f37d7d;
        text-align: left;
      }
      .left{
        margin-left: 16px;
        margin-right: 0;
      }
      .right{
        text-align: right;
      }
    }
  }
}
</style>
image.png
  • 还有一步就是,顶部的对方的名字 需要渲染出来,无非就是在上一级页面跳转的时候多传一个参数,然后这个页面接收渲染一下即可,同学们自己来试试呢??


  • 浅谈socketIO双向通信数据交换技术

  • 何为socketIO?

  • Socket.IO是一个库,基于 Node.js 的实时应用程序框架。可以在浏览器和服务器之间实现实时,双向和基于事件的通信。它适用于每个平台、浏览器或设备,同样注重可靠性和速度。
  • 起源:

  • WebSocket 的产生源于 Web 开发中日益增长的实时通信需求,对比基于 http 的轮询方式,它大大节省了网络带宽,同时也降低了服务器的性能消耗。
  • WebSocket 协议在2008年诞生,2011年成为国际标准。虽然主流浏览器都已经支持,但仍然可能有不兼容的情况,为了兼容所有浏览器,就诞生SocketIO。
  • SocketIO将WebSocket、AJAX和其它的通信方式全部封装成了统一的通信接口,也就是说,我们在使用SocketIO时,不用担心兼容问题,底层会自动选用最佳的通信方式。
  • Socket.io有什么特点?

  • 易用性:Socket.io封装了服务端和客户端,使用起来非常简单方便。
  • 跨平台:Socket.io是跨平台的,可以实现多平台的即时通讯,Socket.io支持跨平台,这就意味着你有了更多的选择,可以在自己喜欢的平台下开发实时应用。由于 iOS 端进行 socket 编程主要使用 GCDAsyncSocket 框架,但要实现 Android、iOS、web 多平台的通讯,还是选择统一的框架或协议比较好。
  • 自适应:Socket.io 实现了实时双向的基于事件的通讯机制,是基于 webSocket 的封装,但它不仅仅包括 webSocket,还对轮询(Polling)机制以及其它的实时通信方式封装成了通用的接口,并且在服务端实现了这些实时机制的相应代码,它会自动根据浏览器从WebSocket、AJAX长轮询、Iframe流等等各种方式中选择最佳的方式来实现网络实时应用,非常方便和人性化,而且支持的浏览器最低达IE5.5。
  • Socket.io 常用内置事件、方法

  • connect 连接socket服务方法(客户端可使用)
  • connection 监听客户端连接的事件(服务端使用on监听使用)
  • disconnect 监听客户端断开链接的事件 (服务端使用on监听使用)
  • emit 注册自定义事件方法(客户端、服务端均可使用)
  • on 监听自定义事件方法(客户端、服务端均可使用)

  • Scoket.io的实际应用

  • (注意:前后端都需要使用Socket.io才能通信)
  • 服务端,基于node.js搭建服务端,需要安装socket.io插件

cnpm install socket.io --save

---- 代码演示过程

var express = require('express');
var router = express.Router();
/**
 * socket.io
 */
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server, {
  transports: ['websocket']
});
server.listen(3001);
/**
 * 监听客户端连接
 */
io.on('connection', function (socket) {
  console.log("客户端连接成功~");
});


module.exports = router;

  • app.js引入这个文件,如果引入过了 就不需要再重复引入了
require("./routes/index")
  • 后端socket服务搭建完成,socket服务地址是: ws://localhost:3001

  • 客户端,基于vue.js搭建客户端,需要安装socket.io-client插件和vue-socket.io-extended插件

cnpm  install socket.io-client vue-socket.io-extended --save
  • main.js内引入自定义js文件socketIo.js
// 引入socket
import './utils/socketIo'
  • socketIo.js

import Vue from 'vue'
import VueSocketIOExt from 'vue-socket.io-extended';
import io from 'socket.io-client';
// 链接websocket
const socket = io.connect('ws://localhost:3001', {
    transports: ['websocket'],
})
Vue.use(VueSocketIOExt, socket);
image.png

image.png
  • 上图就是前后端建立了一个socket通讯服务
  • 下面演示如果进行事件的注册,事件的监听

  • 比如在前端链接上socket服务后,就立马推送一条消息给服务端,然后,服务端推送给所有客户端,说【xxx上线了,并说:xxxxx】

比如在chatDetail页面mounted生命周期内直接执行事件注册方法

mounted () {
      this.$socket.client.emit('sayHello', {
      name: this.$route.query.name == '孙悟空' ? '唐僧' : '孙悟空',
      message: this.$route.query.name == '孙悟空' ? '为师想留在女儿国~' : '俺老孙来也~'
    })
  },
image.png
  • 服务端需要监听一下这个sayHello事件,并广播给除自己外的所有人

/**
 * 监听客户端连接
 */
io.on('connection', function (socket) {
  console.log("客户端连接成功~");
  //广播给除发送者外的所有人
  socket.on("sayHello",data=>{
    socket.broadcast.emit("broMsg",data)
  })
});
image.png
  • vue前端监听服务端推送的信息
sockets:{
    broMsg: function (data) {
      this.info = data
    }
},
  • 然后简单处理下前端页面
 <div class="test" v-if="info" style="font-size: 12px;text-align: center;">
        <span>{{info.name}}</span>上线了,并说了一句<span>{{info.message}}</span>
</div>
  • 最终效果

image.png
  • 这还是只是广播形式的双向通信,如果要实现一对一的的实时通讯,服务端在推送的时候就要使用

  • to(toId)这个方法了,toId就是对方的唯一标识,只有这样才能推给对方,广播是推给除了自己外的所有人

  • 下面来实现一对一通讯

  • 1、就在chatDetail页面,点击发送按钮 ,发送消息
image.png
methods:{
   sendMsg() {
      if (this.value.trim() == '') {
        this.$toast('请输入聊天内容')
        return
      }
      let obj = {
        come_id: this.$route.params.id, //接收方的id
        send_id: this.userName._id, //发送方的id
        type: 1, //消息类型 1 文字消息
        send_avatar: this.userName.avatar, //发送者的头像
        message: this.value, //发送的文字内容
        send_name: this.userName.nickname, //发送者的昵称
        date:new Date(),//发送的当前时间
      }
      this.$socket.client.emit('sayOne', obj)
    }
}
  • 前端部分暂时告一段落,下面是【服务端】监听sayOne事件

image.png
  • 服务端监听到前端发来的数据,利用to(toId)方法发送给对方
  • 在开发服务端前,前端还是要注册触发一个login事件,传给后端来做【socket用户组】
  • 在刚进入这个页面的时候,也就是在mounted生命周期内,注册触发login事件
this.$socket.client.emit('login', this.userName._id)
  • 服务端来监听login事件,作用域外部定义一个空对象hashName,用来存储【socket用户组】
socket.on("login", data => {
    // console.log(data);
    var _id = data;
    hashName[_id] = socket.id;
})
  • 服务端监听sayOne事件
 /** 监听sayOne事件 */
  socket.on('sayOne', data => {
    // console.log(data);
    var toName = data.come_id;
    // console.log(hashName);
    // console.log(hashName[toName]);
    if (hashName[toName]) {
      socket.to(hashName[toName]).emit('message', data)
    }
  })
  • 下面回到前端,在sockets方法函数里,监听服务端注册message事件,得到服务端推过来的消息
 sockets: {
    message:function(data){
      // console.log(data);
      this.$refs.childCom.list.push(data)
    },
  },
  • 如下图
image.png
  • 最后一步,在push下list数组,渲染右侧数据

image.png
sendMsg() {
      if (this.value.trim() == '') {
        this.$toast('请输入聊天内容')
        return
      }
      let obj = {
        come_id: this.$route.params.id, //接收方的id
        send_id: this.userName._id, //发送方的id
        type: 1, //消息类型 1 文字消息
        send_avatar: this.userName.avatar, //发送者的头像
        message: this.value, //发送的文字内容
        send_name: this.userName.nickname, //发送者的昵称
        date:new Date(),//发送的当前时间
      }
      this.$socket.client.emit('sayOne', obj)
      this.$refs.childCom.list.push(obj)

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

推荐阅读更多精彩内容