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实现即时通讯简易聊天室功能,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]