首页 > 开发 > JS > 正文

nodejs和react实现即时通讯简易聊天室功能

2024-05-06 16:54:22
字体:
来源:转载
供稿:网友

npx create-react-app socketio-demo

进入socketio-demo目录 运行eject进行拆包,本项目也可以不拆,这是个人习惯。 注意如果运行eject命令最好在项目初始阶段执行,已经开始编写后不要再使用容易出现bug,新人谨慎使用eject命令

yarn eject

项目拆包后创建服务器文件夹和文件

mkdir servertype null>index.js

创建完成后目录如下

nodejs,react,即时通讯,聊天室

编写即时通讯(聊天室)后台

安装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 srcmkdir iocd iotype null>login.jstype null>socket-demo.jstype null>socket-demo.cssmkdir authcd authtype null>auth.js

创建完成后目录如下

nodejs,react,即时通讯,聊天室

这里auth.js文件是用来判断用户是否输入昵称,如已输入昵称可以进入聊天室,如没有输入昵称则跳回登录界面要求输入昵称

本项目当中我们把昵称存在redux里实现登录界面和聊天室界面的共用,当然现这个项目比较小,如果想用localStorage存在本地也可以,不过考虑到后期的扩展性以及加深对redux的理解我还是选择存在redux当中

src文件夹下创建redux.js文件

src文件夹下创建redux文件夹,在redux文件夹下创建user.redux.js文件

cd srctype null>redux.jsmkdir reduxcd reduxtype null>user.redux.js

新建目录如下

nodejs,react,即时通讯,聊天室

在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实现即时通讯简易聊天室功能,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!


注:相关教程知识阅读请移步到JavaScript/Ajax教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表