腔调 发表于 2023-1-2 09:42:46

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

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

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

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

https://img.jbzj.com/file_images/article/202111/2021112316441789.png
https://img.jbzj.com/file_images/article/202111/2021112316441790.jpg
https://img.jbzj.com/file_images/article/202111/2021112316441791.png
使用方法:

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组件封装,结构及代码
https://img.jbzj.com/file_images/article/202111/2021112316441792.png
(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模拟消息:
https://img.jbzj.com/file_images/article/202111/2021112316441793.png
到此这篇关于前端监听websocket消息并实时弹出的文章就介绍到这了,更多相关websocket消息监听内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多支持脚本之家!

来源:https://www.jb51.net/html5/798933.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 前端监听websocket消息并实时弹出(实例代码)