- 这节课来对接
通讯录好友列表接口
和好友聊天记录接口
· -
对接通讯录好友列表接口
- 打开接口文档https://www.showdoc.com.cn/2035654172307363/9197156730533694
-
1、打开项目,复制对应的接口路径到项目的
src/api/index.js
中
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();
}
-
然后就获取到数据了~
-
6、最后for循环这个list数组,进行数据绑定就搞定了这个通讯录好友列表了
-
对接好友聊天记录接口
-
1、打开接口文档https://www.showdoc.com.cn/2035654172307363/9197322103805778
-
2、复制对接的接口地址路径到
src/api/index.js
文件中粘贴
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();
},
-
然后就获取到数据了~
-
9、下面就是要渲染该数据了,但是因为我们中间的区域是引入的外部组件,所以要先把得到的list数组数据,
通过父子组件传值的形式
,传递过去,子组件使用props
来接收传递过去的数组 -
在子组件身上v-bind动态绑定传值
-
子组件内部使用
props
接收传递过来的list
-
子组件data中的list没用了,就可以删除掉了!!!
-
10、下面就是要处理下渲染出来的数据,根据实际情况渲染,目前是这个样子的
-
先渲染右侧数据,【我是你师傅】和【悟空好绕啊】这两条消息我们现在登陆的这个唐僧的账号发出的,所以,根据接口返回数据和接口返回字段对比
- 如果将我们当前登录账户人发送的消息渲染在右侧呢?
- 其他
send_id
是发送者的id,那谁是发送者呢?当然是当前登录的账户人是发送者,那么将此send_id
和当前登录账户人的个人id
进行对比,如果相等就是渲染在右侧的! -
send_id
有了,现在的问题是如何获取到当前登录账户人的id呢? - 这就需要修改下
获取个人信息
接口存储的数据 - 打开
src/store/modules/app.js
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就在里面
-
11、我们可以通过vuex的
mapGetters
来拿到上图中的对象数据 -
先在
chatDetail
页面引入mapGetters
import { mapGetters } from 'vuex';
-
在通过计算属性拿到
userName
对象
computed: {
...mapGetters(['userName'])
},
-
12、下面就可以渲染右侧的聊天记录数据了
-
那么右侧的数据就渲染好了,在渲染下头像
send_avatar
就搞定右侧了
13、下面来分析下如何渲染左侧数据
- 首先 我们的地址栏参数,那个id就是对方的id,也就是和谁聊天的那个人的id,那么针对左侧的聊天记录来说,左侧的消息是谁发的呢?是对方发的,那么对方就是发送方,那左侧聊天信息的send_id就是发送方的id,那么既然
地址栏参数,那个id就是对方的id
,那地址栏的id==左侧聊天信息的send_id
是不是就可以渲染左侧数据了呢
-
搞定!!!
<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>
-
还有一步就是,顶部的对方的名字 需要渲染出来,无非就是在上一级页面跳转的时候多传一个参数,然后这个页面接收渲染一下即可,同学们自己来试试呢??
-
浅谈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);
-
上图就是前后端建立了一个socket通讯服务
-
下面演示如果进行事件的注册,事件的监听
-
比如在前端链接上socket服务后,就立马推送一条消息给服务端,然后,服务端推送给所有客户端,说【xxx上线了,并说:xxxxx】
比如在chatDetail
页面mounted
生命周期内直接执行事件注册方法
mounted () {
this.$socket.client.emit('sayHello', {
name: this.$route.query.name == '孙悟空' ? '唐僧' : '孙悟空',
message: this.$route.query.name == '孙悟空' ? '为师想留在女儿国~' : '俺老孙来也~'
})
},
-
服务端需要监听一下这个
sayHello
事件,并广播给除自己外的所有人
/**
* 监听客户端连接
*/
io.on('connection', function (socket) {
console.log("客户端连接成功~");
//广播给除发送者外的所有人
socket.on("sayHello",data=>{
socket.broadcast.emit("broMsg",data)
})
});
-
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>
-
最终效果
-
这还是只是广播形式的双向通信,如果要实现一对一的的实时通讯,服务端在推送的时候就要使用
-
to(toId)这个方法了,
toId
就是对方的唯一标识,只有这样才能推给对方,广播是推给除了自己外的所有人 -
下面来实现一对一通讯
-
1、就在
chatDetail
页面,点击发送按钮 ,发送消息
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
事件
-
服务端监听到前端发来的数据,利用
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)
},
},
-
如下图
-
最后一步,在push下list数组,渲染右侧数据
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)
}
-
如下图,已经实现了一对一通讯
-
在最后一步,格式化下时间即可
{{$formatDate(item.date,'yyyy-MM-dd hh:mm:ss')}}