最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

nodejs和react實(shí)現(xiàn)即時(shí)通訊簡(jiǎn)易聊天室功能

 更新時(shí)間:2019年08月21日 09:30:00   作者:yanerl  
這篇文章主要介紹了nodejs和react實(shí)現(xiàn)即時(shí)通訊簡(jiǎn)易聊天室功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

npx create-react-app socketio-demo

進(jìn)入socketio-demo目錄 運(yùn)行eject進(jìn)行拆包,本項(xiàng)目也可以不拆,這是個(gè)人習(xí)慣。 注意如果運(yùn)行eject命令最好在項(xiàng)目初始階段執(zhí)行,已經(jīng)開始編寫后不要再使用容易出現(xiàn)bug,新人謹(jǐn)慎使用eject命令

yarn eject

項(xiàng)目拆包后創(chuàng)建服務(wù)器文件夾和文件

mkdir server
type null>index.js

創(chuàng)建完成后目錄如下

 

編寫即時(shí)通訊(聊天室)后臺(tái)

安裝nodejs插件

npm i express http socket.io nodemon

進(jìn)入server文件夾下的index.js頁面開始編寫后臺(tái)程序

const app = require('express')(); 
const server = require('http').Server(app); 
const io = require('socket.io')(server); 
//設(shè)置端口9093 
server.listen(9093); 
//創(chuàng)建socket.io連接 
io.on('connection', function (socket) { 
 //獲取messages事件 
 socket.on('messages', function (data) { 
  //向所有連接進(jìn)行廣播 
 socket.broadcast.emit('messages', data) 
  //對(duì)發(fā)出者進(jìn)行廣播,用戶名加上我 
 data.user=data.user+'[我]' 
 socket.emit('messages', data) 
 }); 
});

編寫即時(shí)通訊(聊天室)前臺(tái)

后臺(tái)編寫完畢,可以在src目錄中編寫前臺(tái)內(nèi)容 安裝需要用到的react-router和redux依賴

npm i redux react-redux react-router react-router-dom

在src中創(chuàng)建io文件夾 在io文件夾中創(chuàng)建所需要的文件

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

創(chuàng)建完成后目錄如下

 

這里auth.js文件是用來判斷用戶是否輸入昵稱,如已輸入昵稱可以進(jìn)入聊天室,如沒有輸入昵稱則跳回登錄界面要求輸入昵稱

本項(xiàng)目當(dāng)中我們把昵稱存在redux里實(shí)現(xiàn)登錄界面和聊天室界面的共用,當(dāng)然現(xiàn)這個(gè)項(xiàng)目比較小,如果想用localStorage存在本地也可以,不過考慮到后期的擴(kuò)展性以及加深對(duì)redux的理解我還是選擇存在redux當(dāng)中

src文件夾下創(chuàng)建redux.js文件

src文件夾下創(chuàng)建redux文件夾,在redux文件夾下創(chuàng)建user.redux.js文件

cd src
type null>redux.js
mkdir redux
cd redux
type null>user.redux.js

新建目錄如下

 

在redux文件夾下的user.redux.js中創(chuàng)建存儲(chǔ)用戶昵稱的reducer

const SET_USERNAME='SET_USERNAME' 
//初始化倉庫 
const initState={user:''} 
//根據(jù)動(dòng)作改變倉庫  
export function User(state = initState, action) { 
 switch (action.type) { 
  case SET_USERNAME: 
   return {...state,user:action.payload} 
  default: 
   return state 
 } 
} 
//寫入昵稱動(dòng)作 
export function setUserName(user) { 
 return { 
  type:SET_USERNAME, 
 payload:user 
 } 
}

在src/redux.js文件中創(chuàng)建倉庫 combineReducers用于多個(gè)reducer的合并,這個(gè)項(xiàng)目中也可以不加,單為了后期擴(kuò)展加入使用

import { combineReducers, createStore } from 'redux' 
import {User} from './redux/user.redux' 
//window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() 用于chrome redux的擴(kuò)展項(xiàng)
let reducer = combineReducers({ User }) 
let store = createStore( 
 reducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()) 
 
export default store

這樣就可以在頁面當(dāng)中使用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 時(shí)安裝 @babel/plugin-proposal-decorators

npm i @babel/plugin-proposal-decorators

在package.json中babel項(xiàng)中配置,注意plugins放在presets前否則容易報(bào)錯(cuò)

"babel": { 
 "plugins": [ 
  ["@babel/plugin-proposal-decorators", { "legacy": true }] 
 ], 
 "presets": [ 
  "react-app" 
 ] 
}

好了這樣就可以使用裝飾付了

下面我們來編寫判斷是否設(shè)置用戶名的程序 打開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

編寫輸入昵稱并跳轉(zhuǎn)步驟 打開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)
 }
 //鍵盤點(diǎn)擊跳轉(zhuǎn) 
 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
  })
 }
 //賦值并跳轉(zhuǎn)到聊天室頁面 
 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}>進(jìn)入聊天室</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連接后臺(tái) 
  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)
 }
 //鼠標(biāo)回車事件 
 onKeyDown(e){
  switch (e.keyCode) {
   case 13:
    this.send();
    return; default:
    return;
  }
 }
 //向后臺(tái)發(fā)送信息 
 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='請(qǐng)?jiān)诖溯斎肓奶煨畔?
          onChange={v=>this.handleChange('message',v)}
          value={this.state.message}
      />
      <button onClick={this.send}>發(fā)送鏈接</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"
},
  • 運(yùn)行后臺(tái) yarn server
  • 運(yùn)行前臺(tái) yarn start

啟動(dòng)程序

總結(jié)

以上所述是小編給大家介紹的nodejs和react實(shí)現(xiàn)即時(shí)通訊簡(jiǎn)易聊天室功能,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!

相關(guān)文章

  • TypeScript在React項(xiàng)目中的使用實(shí)踐總結(jié)

    TypeScript在React項(xiàng)目中的使用實(shí)踐總結(jié)

    這篇文章主要介紹了TypeScript在React項(xiàng)目中的使用總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 淺談React中組件邏輯復(fù)用的那些事兒

    淺談React中組件邏輯復(fù)用的那些事兒

    這篇文章主要介紹了淺談React中組件邏輯復(fù)用的那些事兒,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn)

    React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn)

    本文主要介紹了React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • react-router?重新加回跳轉(zhuǎn)攔截功能詳解

    react-router?重新加回跳轉(zhuǎn)攔截功能詳解

    這篇文章主要為大家介紹了react-router?重新加回跳轉(zhuǎn)攔截功能詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • react hooks實(shí)現(xiàn)原理解析

    react hooks實(shí)現(xiàn)原理解析

    這篇文章主要介紹了react hooks實(shí)現(xiàn)原理,文中給大家介紹了useState dispatch 函數(shù)如何與其使用的 Function Component 進(jìn)行綁定,節(jié)后實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • 使用React和Redux Toolkit實(shí)現(xiàn)用戶登錄功能

    使用React和Redux Toolkit實(shí)現(xiàn)用戶登錄功能

    在React中,用戶登錄功能是一個(gè)常見的需求,為了實(shí)現(xiàn)該功能,需要對(duì)用戶輸入的用戶名和密碼進(jìn)行驗(yàn)證,并將驗(yàn)證結(jié)果保存到應(yīng)用程序狀態(tài)中,在React中,可以使用Redux Toolkit來管理應(yīng)用程序狀態(tài),從而實(shí)現(xiàn)用戶登錄功能,需要詳細(xì)了解可以參考下文
    2023-05-05
  • React實(shí)現(xiàn)卡片拖拽效果流程詳解

    React實(shí)現(xiàn)卡片拖拽效果流程詳解

    這篇文章主要介紹了React Web開發(fā)實(shí)戰(zhàn)示例,實(shí)現(xiàn)卡片拖拽效果,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-11-11
  • react antd-design Select全選功能實(shí)例

    react antd-design Select全選功能實(shí)例

    這篇文章主要介紹了react antd-design Select全選功能實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • react 組件實(shí)現(xiàn)無縫輪播示例詳解

    react 組件實(shí)現(xiàn)無縫輪播示例詳解

    這篇文章主要為大家介紹了react 組件實(shí)現(xiàn)無縫輪播示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 解決jest處理es模塊示例詳解

    解決jest處理es模塊示例詳解

    這篇文章主要為大家介紹了解決jest處理es模塊示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02

最新評(píng)論

遂平县| 黑龙江省| 阿克| 巨野县| 新兴县| 乐业县| 恩施市| 清流县| 万安县| 绥宁县| 京山县| 香河县| 土默特左旗| 专栏| 桐梓县| 平邑县| 武陟县| 鹤岗市| 吉木乃县| 于田县| 内乡县| 桦南县| 高陵县| 泸定县| 大田县| 准格尔旗| 师宗县| 福州市| 唐海县| 淮阳县| 佛教| 饶平县| 铜陵市| 读书| 昌乐县| 翁牛特旗| 洱源县| 游戏| 台州市| 宁南县| 探索|