您好,登錄后才能下訂單哦!
使用nodejs和react怎么實現一個即時通訊聊天室功能?相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
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怎么實現一個即時通訊聊天室功能的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。