前端监听websocket消息并实时弹出

Posted HeavyShell

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端监听websocket消息并实时弹出相关的知识,希望对你有一定的参考价值。

本文默认您已掌握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模拟消息:

 

 结束:Over 

 

 

以上是关于前端监听websocket消息并实时弹出的主要内容,如果未能解决你的问题,请参考以下文章

前端监听websocket消息并实时弹出

前端监听websocket消息并实时弹出

利用websocket+Vuex完成一个实时聊天软件(前端部分)

WebSocket Session共享

如何使用 websockets 监听 mongodb 中的更新

如何从 GDAX websocket feed 获取实时出价/要价/价格