后端下载依赖:
yarn add socket.io // 采用socket.io进行实时通信
在router/index.js中配置连接
var express = require('express');
var router = express.Router();
const http = require('http');
const socketIO = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketIO(server, {
cors: {
origin: '*'
}
});
// 在线用户列表
let userList = []
// 用户连接
io.on('connection', (socket) => {
console.log('用户连接成功');
let userSocketId = socket.id;
// 初始化 数据
socket.on('userData', (data) => {
let idx = userList.findIndex(item => {
return item._id === data._id
})
if (idx === -1) {
userList.push(data)
}
io.emit('online', userList)
// 设置当前用户的userid
socket.emit('userid', { user: data, userId: userSocketId, })
});
// 接收客户端发送的消息
socket.on('message', ({ partner, user, message }) => {
socket.to(partner.userID).emit('sendOne', message)
})
// 用户离开
socket.on('disconnect', () => {
console.log('用户离开');
});
// 离开时 获取到的 用户信息
socket.on('leave', (data) => {
let idx = userList.findIndex(item => item._id === data._id);
// 离开时 删除在线人员
userList.splice(idx, 1)
// 离开时 更新在线人员
io.emit('online', userList)
})
});
server.listen(3000, () => {
console.log('Server is running on port 3000');
});
前端依赖
yarn add socket.io-client // 前端采用 socket.io-client 来实现实时通信
import React, { useEffect, useState } from 'react'
import '../css/DetailChat.scss'
import { useLocation, useNavigate } from 'react-router-dom'
import { Toast, NavBar, Input, Button } from 'react-vant';
import { WapNav } from '@react-vant/icons';
import io from 'socket.io-client';
import axios from 'axios';
export default function DetailChat() {
const socket = io('http://localhost:3000'); // 指定服务器的URL
let location = useLocation()
const Navigate = useNavigate()
// 对象数据
let partner = location.state;
// 当前用户数据
let userData = JSON.parse(sessionStorage.getItem('user')) || []
// 定义输入框的信息
const [iptValue, setIptValue] = useState('')
// 保存聊天记录
const [record, setRecord] = useState([])
// 发送消息
const send = async () => {
let { data } = await axios.get(`http://localhost:3002/getPartner?id=${partner._id}&uid=${userData._id}&message=${iptValue}`)
if (data.code === 200) {
socket.emit('message', { partner: data.data[0], user: data.data[1], message: iptValue })
setIptValue('')
getrecord()
}
}
// 用户连接
useEffect(() => {
getrecord()
socket.on('connect', () => {
// 发送用户信息到服务器
socket.emit('userData', userData);
// 设置userid
socket.on('userid', data => {
saveData(data)
})
})
// 接收数据
socket.on('sendOne', (data) => {
getrecord()
})
return () => {
socket.emit('leave', userData) // 离开时传递 用户信息
socket.disconnect(); // 组件卸载时断开连接
};
}, []);
// 监听新消息保持在最底部--- 获取最后一条消息
useEffect(() => {
let lasrChild = document.querySelector('.detailChat-message').lastElementChild
if (lasrChild) {
lasrChild.scrollIntoView(false)
}
}, [record])
// 初始化 --- 保存用户的连接 id
const saveData = async (user) => {
await axios.post('http://localhost:3002/saveData', user)
}
// 获取聊天记录
const getrecord = async () => {
let { data } = await axios.get(`http://localhost:3002/getrecord?user1=${partner._id}&user2=${userData._id}`)
setRecord(data.data)
}
// 返回
const goback = () => {
Navigate('/chat')
}
return (
<div className='detailChat'>
{/* 个人聊天 -- 顶部区域 */}
<div className='detailChat-top'>
<NavBar
title={partner.userName}
// leftText={ }
rightText={<WapNav />}
onClickLeft={goback}
onClickRight={() => Toast('按钮')}
/>
</div>
{/* 聊天记录显示区域 */}
<div className='detailChat-message'>
{
record.map((item, index) => {
return (
<div className='detailChat-item' key={index}>
{
item.sendUser === userData._id ?
<div style={{ textAlign: 'right',paddingRight: '.5rem'}}>
<div className='detailChat-item-right'>{item.message}</div>
<img src={userData.headPortrait} alt="" />
</div>
:
<div style={{ textAlign: 'left', paddingLeft: '.5rem' }}>
<img src={partner.headPortrait} alt="" />
<div className='detailChat-item-left'>{item.message}</div>
</div>
}
</div>
)
})
}
</div>
{/* 个人聊天 -- 底部输入区域 */}
<div className='detailChat-bottom'>
<Input
value={iptValue}
onChange={(value) => setIptValue(value)}
onKeyDown={(e) => e.keyCode === 13 ? send() : ''}
prefix="💁"
suffix={<Button size="small" type="primary" onClick={send} >发送</Button>}
placeholder="请输入发送的内容"
/>
</div>
</div>
)
}
实现效果展示:
WebSocket的实现