用户登录
用户注册

分享至

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实现即时通讯简易聊天室功能,希望对大家有所帮助

软件
前端设计
程序设计
Java相关