npx create-react-app socketio-demo
	進入socketio-demo目錄 運行eject進行拆包,本項目也可以不拆,這是個人習慣。 注意如果運行eject命令最好在項目初始階段執行,已經開始編寫后不要再使用容易出現bug,新人謹慎使用eject命令
	yarn eject
項目拆包后創建服務器文件夾和文件
mkdir servertype 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 srcmkdir iocd iotype null>login.jstype null>socket-demo.jstype null>socket-demo.cssmkdir authcd authtype null>auth.js
創建完成后目錄如下
這里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
新建目錄如下
在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"},啟動程序
總結
以上所述是小編給大家介紹的nodejs和react實現即時通訊簡易聊天室功能,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的!
新聞熱點
疑難解答