前端監(jiān)聽(tīng)websocket消息并實(shí)時(shí)彈出(實(shí)例代碼)

本文默認(rèn)您已掌握react生態(tài)開(kāi)發(fā)的相關(guān)技術(shù),并熟練應(yīng)用umiJS的原則上,請(qǐng)繼續(xù)!
項(xiàng)目需求:
1、服務(wù)側(cè)推送給消息給前端,前端需要展示在右下角
2、根據(jù)不同的消息類(lèi)型,提供不同的操作按鈕‘同意’、‘拒絕’等
代碼設(shè)計(jì):
1、使用websocket方式建立通道
2、前端基于umi+antd+reconnecting-websocket.js開(kāi)發(fā)
3、使用express+express-ws+mockjs建立websocket服務(wù)通道,模擬服務(wù)端推送消息
運(yùn)行效果:
使用方法:
1、項(xiàng)目中已引入reconnecting-websocket.min.js,詳見(jiàn)其官方文檔
2、登錄成功后,接著調(diào)用websocket初始化:
yield put({ type: 'websocket/init', payload: { authToken } });
核心代碼:
1、/service/websocket.js
/** * 基于reconnecting-websocket庫(kù)已引入 * 封裝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(); } // 關(guān)閉連接 export function closeWs() { return websocket.close(); } // 監(jiān)聽(tīng)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組件請(qǐng)自行學(xué)習(xí) */ 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']); // 監(jiān)聽(tīng)退出系統(tǒng),則關(guān)閉websocket if (type === 'logout') { // 關(guān)閉websocket yield call(closeWs); notification.destroy(); yield put({ type: 'clearAllMessage', payload:{ } }); } } }, // 啟動(dòng)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) } }); } }, // 統(tǒng)籌消息 * 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組件封裝,結(jié)構(gòu)及代碼
(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); } }); }) } // 關(guān)閉消息 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模擬消息:
到此這篇關(guān)于前端監(jiān)聽(tīng)websocket消息并實(shí)時(shí)彈出的文章就介紹到這了,更多相關(guān)websocket消息監(jiān)聽(tīng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持腳本之家!
相關(guān)文章
五分鐘學(xué)會(huì)HTML5的WebSocket協(xié)議
這篇文章主要介紹了五分鐘學(xué)會(huì)HTML5的WebSocket協(xié)議,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)2019-11-22websocket+sockjs+stompjs詳解及實(shí)例代碼
這篇文章主要介紹了websocket+sockjs+stompjs詳解及實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-30html5 http的輪詢(xún)和Websocket原理
這篇文章主要介紹了html5 http的輪詢(xún)和Websocket原理的相關(guān)資料,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-19- 這篇文章主要介紹了基于HTML5的WebSocket的實(shí)例代碼,需要的朋友可以參考下2018-08-15