前端监听websocket消息并实时弹出(实例代码)

ID:16198 / 打印

本文默认您已掌握react生态开发的相关技术,并熟练应用umiJS的原则上,请继续!

项目需求:

1、服务侧推送给消息给前端,前端需要展示在右下角
2、根据不同的消息类型,提供不同的操作按钮‘同意’、‘拒绝’等

代码设计:

1、使用websocket方式建立通道
2、前端基于umi+antd+reconnecting-websocket.js开发
3、使用express+express-ws+mockjs建立websocket服务通道,模拟服务端推送消息

运行效果:

使用方法:

1、项目中已引入reconnecting-websocket.min.js,详见其官方文档

2、登录成功后,接着调用websocket初始化:

 yield put({     type: 'websocket/init',     payload: {         authToken     } });

核心代码:

1、/service/websocket.js

 /**  * 基于reconnecting-websocket库已引入  * 封装service文件  */ class Websocket{     /**    * websocket逻辑    * 2021-10-28    */     constructor(){     this.websocket=null;     this.url='ws://127.0.0.1:30001/websocket-im';     this.options={       connectionTimeout: 5000,       maxRetries: 10,     };   }     init=()=>{     this.websocket = new ReconnectingWebSocket(this.url,[], this.options);   }     close=()=>{     this.websocket && this.websocket.close();   }     onMessage=(callback)=>{     this.websocket && this.websocket.addEventListener('message', (e) => {       callback&&callback(e)     });   }   }   const websocket = new Websocket();   // 初始化连接 export function openWs() {   return websocket.init(); }   // 关闭连接 export function closeWs() {   return websocket.close(); }   // 监听websocket消息 export function onMessage() {   let deferred;   websocket.onMessage(function(e){     if(deferred) {         deferred.resolve(e)         deferred = null      }   });   return {     message() {       if(!deferred) {           deferred = {}           deferred.promise = new Promise(resolve => deferred.resolve = resolve)       }       return deferred.promise;     }   } }  

2、/model/websocket.js

   /**  * 封装model文件  * moment、immutable、antd、nanoid组件请自行学习  */ import {openWs,onMessage,closeWs} from 'services/websocket' import moment from 'moment' import { Map, fromJS } from 'immutable' import { notification } from 'antd' import nanoid from 'nanoid';   const initState = Map({     message:Map(), //收到的消息    }); export default {   namespace: 'websocket',     state: initState,   subscriptions: {     setup({ dispatch, history }) {       dispatch({         type: 'listener'       });       return history.listen(({ pathname, query }) => {                });     },   },   effects: {       * listener({ payload }, { take, put, call }) {       while (true) {         const { type, payload } = yield take(['logout']);                  // 监听退出系统,则关闭websocket         if (type === 'logout') {           // 关闭websocket           yield call(closeWs);           notification.destroy();           yield put({             type: 'clearAllMessage',              payload:{             }           });         }       }     },       // 启动websocket     * init ({       payload,     }, { put, call, select }) {       yield call(openWs);       const listener = yield call(onMessage);       yield put({type: 'receiveMsg', payload:{listener}});     },        // 接受消息     * receiveMsg ({         payload: {listener}     }, { call, select, put}) {         while(true){           const event = yield call(listener.message);             yield put({             type: 'progressMsg',              payload:{               msg:JSON.parse(event.data)             }           });                                 }     },       // 统筹消息     * progressMsg ({         payload: {msg}     }, { call, select, put}) {         console.log(msg)              yield put({         type: 'addOneMessage',          payload:{           msg         }       });              },     },      reducers: {          addOneMessage(state, { payload:{msg} }) {           const msgId = nanoid()+'-'+moment().format('x');       return state.setIn(['message',msgId], fromJS({...msg,msgId}))       },       removeOneMessage(state, { payload:{msgId} }) {           return state.deleteIn(['message',msgId])       },       clearAllMessage(state, { payload:{} }) {           return state.setIn(['message'],Map())       },          },    }

3、Notification组件封装,结构及代码

 

(1)package.json

 {   "name": "Notification",   "version": "0.0.0",   "private": true,   "main": "./index.js" }

(2) index.less

 .Notification{     .btns{         padding: 0;         margin: 15px 0 0 0;         list-style: none;         width: 100%;         display: flex;         justify-content: flex-end;         li{             margin-left: 10px;         }     } }

(3)index.js

 /**  * 右下角弹窗组件封装  */ import React from 'react' import { injectIntl } from 'react-intl'; import moment from 'moment' import { connect } from 'dva' import { notification } from 'antd'; import Demo1 from './Demo1' import Demo2 from './Demo2'   @injectIntl @connect(({   websocket,  }) => ({    websocket })) export default class Notification extends React.Component {     componentWillReceiveProps(nextProps) {     const {websocket,dispatch,intl, intl: { formatMessage }} = nextProps;     let message=websocket.get('message');       message.forEach((note)=>{         let object=note.getIn(['object']);       let msgId=note.getIn(['msgId']);       let title=note.getIn(['title']);       let content=note.getIn(['content']);       let format = 'YYYY-MM-DD HH:mm:ss';       let time=note.getIn(['ts'])?moment(note.getIn(['ts']), 'x').format(format):moment().format(format);         switch (object) {         case 'demo1':           content=<Demo1 						dispatch={dispatch} 						intl={intl} 						note={note} 						onClose={()=>this.onClose(msgId)} 					/>; 					break;         case 'demo2':           content=<Demo2             dispatch={dispatch}             intl={intl}             note={note}             onClose={()=>this.onClose(msgId)}           />;           break;         default: 					break; 			}         notification.open({         message: <span>{title} <small>{time}</small></span>,         duration:30,         key: msgId,         description:content,         placement: 'bottomRight',         onClick: () => {                    },         onClose: () => {           this.onClose(msgId);         }       });     })     }     // 关闭消息   onClose=(msgId)=>{     const {dispatch} = this.props;     dispatch({       type:'websocket/removeOneMessage',       payload:{         msgId       }     })     return notification.close(msgId);   }      render(){     return(         null     )   }    }     Notification.propTypes = {    }

(4)Demo1.js

 import React from 'react' import styles from './index.less'   export default class NotificationSon extends React.Component {      render(){     const {note,intl:{formatMessage}} = this.props;     let content=note.getIn(['content']);       return(         <div className={styles.Notification}>           <div>{content}</div>         </div>     )   }    }   NotificationSon.propTypes = {    }

(5)Demo2.js 

 import React from 'react' import styles from './index.less' import { config } from 'utils' import { Button } from 'antd';   const { defaultStyleSize } = config;   export default class NotificationSon extends React.Component {     dealApproval=(type,data)=>{     const {dispatch,onClose} = this.props;     if(type=='refuse'){       console.log('拒绝')       onClose();     }else if(type=='agree'){       console.log('同意')       onClose();     }        }      render(){     const {note,intl:{formatMessage}} = this.props;     let content=note.getIn(['content']);       return(         <div className={styles.Notification}>           <div>{content}</div>           <ul className={styles.btns}>             <li>               <Button style={{ marginLeft: '12px' }} type={'primary'} size={defaultStyleSize}  onClick={() => {this.dealApproval('agree',note.get('data'))}}>{formatMessage({id: 'Global.agree'})}</Button>             </li>             <li>               <Button style={{ marginLeft: '12px' }} type={'danger'} size={defaultStyleSize}  onClick={() => {this.dealApproval('refuse',note.get('data'))}}>{formatMessage({id: 'Global.refuse'})}</Button>             </li>           </ul>         </div>     )   }    }   NotificationSon.propTypes = {    }

express模拟消息:

上一篇: Html5获取用户当前位置的几种方式
下一篇: Html5同时支持多端sdk的小技巧

作者:admin @ 24资源网   2024-11-01

本站所有软件、源码、文章均有网友提供,如有侵权联系308410122@qq.com

与本文相关文章

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。