nodejs和react实现即时通讯简易聊天室功能
- 作者: 听说段子很搞笑
- 来源: 51数据库
- 2021-08-16
npx create-react-app socketio-demo
进入socketio-demo目录 运行eject进行拆包,本项目也可以不拆,这是个人习惯。 注意如果运行eject命令最好在项目初始阶段执行,已经开始编写后不要再使用容易出现bug,新人谨慎使用eject命令
yarn eject
项目拆包后创建服务器文件夹和文件
mkdir server type null>index.js
创建完成后目录如下
编写即时通讯(聊天室)后台
安装nodejs插件
npm i express http socket.io nodemon
进入server文件夹下的index.js页面开始编写后台程序
const app = require('express')();
const server = require('http').server(app);
const io = require('socket.io')(server);
//设置端口9093
server.listen(9093);
//创建socket.io连接
io.on('connection', function (socket) {
//获取messages事件
socket.on('messages', function (data) {
//向所有连接进行广播
socket.broadcast.emit('messages', data)
//对发出者进行广播,用户名加上我
data.user=data.user+'[我]'
socket.emit('messages', data)
});
});
编写即时通讯(聊天室)前台
后台编写完毕,可以在src目录中编写前台内容 安装需要用到的react-router和redux依赖
npm i redux react-redux react-router react-router-dom
在src中创建io文件夹 在io文件夹中创建所需要的文件
cd src mkdir io cd io type null>login.js type null>socket-demo.js type null>socket-demo.css mkdir auth cd auth type null>auth.js
创建完成后目录如下
这里auth.js文件是用来判断用户是否输入昵称,如已输入昵称可以进入聊天室,如没有输入昵称则跳回登录界面要求输入昵称
本项目当中我们把昵称存在redux里实现登录界面和聊天室界面的共用,当然现这个项目比较小,如果想用localstorage存在本地也可以,不过考虑到后期的扩展性以及加深对redux的理解我还是选择存在redux当中
src文件夹下创建redux.js文件
src文件夹下创建redux文件夹,在redux文件夹下创建user.redux.js文件
cd src type null>redux.js mkdir redux cd redux type null>user.redux.js
新建目录如下
在redux文件夹下的user.redux.js中创建存储用户昵称的reducer
const set_username='set_username'
//初始化仓库
const initstate={user:''}
//根据动作改变仓库
export function user(state = initstate, action) {
switch (action.type) {
case set_username:
return {...state,user:action.payload}
default:
return state
}
}
//写入昵称动作
export function setusername(user) {
return {
type:set_username,
payload:user
}
}
在src/redux.js文件中创建仓库 combinereducers用于多个reducer的合并,这个项目中也可以不加,单为了后期扩展加入使用
import { combinereducers, createstore } from 'redux'
import {user} from './redux/user.redux'
//window.__redux_devtools_extension__ && window.__redux_devtools_extension__() 用于chrome redux的扩展项
let reducer = combinereducers({ user })
let store = createstore(
reducer,window.__redux_devtools_extension__ && window.__redux_devtools_extension__())
export default store
这样就可以在页面当中使用redux了
下一步在app.js中引入redux,并把路由搭建起来 在src/app.js中写入
import react from 'react';
import {hashrouter as router,route,switch} from 'react-router-dom'
import login from "./io/login";
import socketdemo from "./io/socket-demo";
import {provider} from 'react-redux'
import store from './redux'
import auth from "./io/auth/auth";
function app() {
return (
<provider store={store}>
<router>
<auth></auth>
<switch>
<route exact path='/' component={login}/>
<route exact path='/talk' component={socketdemo}/>
</switch>
</router>
</provider>
);
}
export default app;
在写页面之前我们先安装修饰符插件
npm i babel-plugin-transform-decorators-legacy
babel >= 7.x 时安装 @babel/plugin-proposal-decorators
npm i @babel/plugin-proposal-decorators
在package.json中babel项中配置,注意plugins放在presets前否则容易报错
"babel": {
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }]
],
"presets": [
"react-app"
]
}
好了这样就可以使用装饰付了
下面我们来编写判断是否设置用户名的程序 打开src/io/auth下的auth.js文件
import react from 'react';
import {connect} from 'react-redux'
import {withrouter} from 'react-router-dom'
//获取reducer
@connect(
state=>state,
{}
)
//获取router
@withrouter
class auth extends react.component{
componentdidmount() {
//如果有用户名就跳到聊天页,如没有则跳到登陆页。
if(this.props.user.user){
this.props.history.push('/talk')
}else {
this.props.history.push('/')
}
}
render() {
return null
}
}
export default auth
编写输入昵称并跳转步骤 打开src/io/login.js文件
import react from 'react';
import './socket-demo.css';
import {connect} from 'react-redux'
import {setusername} from '../redux/user.redux'
@connect(
null,
{setusername}
)
class login extends react.component{
constructor(props) {
super(props);
this.state={
user:''
}
this.login=this.login.bind(this)
this.onkeydown=this.onkeydown.bind(this)
}
//键盘点击跳转
onkeydown(e){
switch (e.keycode) {
case 13:
this.login();
return;
default:
return;
}
}
//添加键盘事件
componentdidmount() {
document.addeventlistener("keydown", this.onkeydown)
}
//赋值state
handlechange(title,target){
this.setstate({
[title]:target.target.value
})
}
//赋值并跳转到聊天室页面
login(){
let {user}=this.state;
if(user!==null && user.trim()!==''){
this.props.setusername(user);
this.props.history.push('/talk')
}
}
render() {
return (
<div classname='logindiv'>
<input type='text' placeholder='输入昵称' onchange={v=>this.handlechange('user',v)} />
<button onclick={this.login}>进入聊天室</button>
</div> );
}
}
export default login
下面是重头戏,聊天室的前端展示的核心代码 打开src/iosocket-demo.js文件
import react from 'react'
import io from 'socket.io-client'
import {connect} from 'react-redux'
import './socket-demo.css'
const url='ws://localhost:9093'
const socket = io(url);
@connect(
state=>state,
{}
)
class socketdemo extends react.component{
constructor(props) {
super(props);
this.state={
message:'',
user:this.props.user.user,
messages:[]
}
this.send=this.send.bind(this)
this.login=this.login.bind(this)
this.onkeydown=this.onkeydown.bind(this)
}
componentdidmount() {
//输入欢迎信息
this.login()
//增加回车事件
document.addeventlistener("keydown", this.onkeydown)
//socket.io连接后台
io(url).on('connect', ()=>{
console.log('connect');
socket.on('messages', data => {
//返回用户列表
this.setstate({
messages:[...this.state.messages,data]
})
if(this.refs.showdiv){
this.refs.showdiv.scrolltop=2000
}
});
});
}
componentwillunmount() {
//断开socket io连接
io('ws://localhost:9093').on('disconnect', function(){
console.log('disconntect');
});
document.removeeventlistener("keydown", this.onkeydown)
}
//鼠标回车事件
onkeydown(e){
switch (e.keycode) {
case 13:
this.send();
return; default:
return;
}
}
//向后台发送信息
send(){
let {user,message}=this.state;
console.log(this.refs.showdiv);
socket.emit('messages', {user,message});
this.setstate({
message:''
})
}
login(){
let user=this.props.user.user;
const obj={user:'作者',message:`欢迎${user}来到聊天室`}
if(user.trim()!==''){
this.setstate({
user:user,
messages:[obj]
})
}
}
//赋值state
handlechange(title,target){
this.setstate({
[title]:target.target.value
})
}
render() {
let cn='showinfo'
return (
<div>
<div classname='talkdiv'>
<div classname='operatingdiv'>
<input type='text'
placeholder='请在此输入聊天信息'
onchange={v=>this.handlechange('message',v)}
value={this.state.message}
/>
<button onclick={this.send}>发送链接</button>
</div> <div ref='showdiv' classname='showdiv'>
{
this.state.messages.map((v,index)=>{
if(index===0){
cn='titleinfo'
}else{
cn='showinfo'
}
return (
<div classname={cn} key={index}>
<span>{v.user}:</span>
<span>{v.message}</span>
</div> )
})
}
</div>
</div>
</div> );
}
}
export default socketdemo;
最后加上src/iosocket-demo.css
body{
background: #008db7;
font-family: 'microsoft yahei ui';
}
.logindiv{
text-align: center;
margin: 150px auto 0;
width: 250px;
}
.logindiv input[type='text']{
display: inline-block;
box-sizing: border-box;
border-radius: 5px;
padding-left: 5px;
border: none;
width: 250px;
height: 35px;
line-height: 35px;
}
.logindiv button{
display: inline-block;
box-sizing: border-box;
border-radius: 5px;
padding-left: 5px;
border: none;
width: 250px;
height: 35px;
line-height: 35px;
margin-top: 10px;
background: #0067a2;
color: #ffffff;
}
.talkdiv{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.talkdiv .operatingdiv{
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 40px;
display: flex;
}
.talkdiv .operatingdiv input[type='text']{
flex: 1;
height: 40px;
line-height: 40px;
box-sizing: border-box;
padding-left: 10px;
}
.talkdiv .operatingdiv button{
display: inline-block;
box-sizing: border-box;
border-radius: 5px;
border: none;
width: 250px;
height: 40px;
line-height: 40px;
background: #0067a2;
color: #ffffff;
}
.talkdiv .showdiv{
position: fixed;
bottom: 40px;
left: 0;
right: 0;
top: 0;
font-size: 16px;
color: #ffffff;
overflow: auto;
}
.talkdiv .showdiv .titleinfo{
padding: 10px;
color: yellow;
font-size: 20px;
}
.talkdiv .showdiv .showinfo{
padding: 10px;
}
在package.json中加入命令行
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js",
"server": "nodemon server/index.js"
},
- 运行后台 yarn server
- 运行前台 yarn start
启动程序
总结
以上所述是小编给大家介绍的nodejs和react实现即时通讯简易聊天室功能,希望对大家有所帮助
