前端監(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ù)不同的消息類型,提供不同的操作按鈕‘同意’、‘拒絕’等
代碼設(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-30
這篇文章主要介紹了html5 http的輪詢和Websocket原理的相關(guān)資料,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-19- 這篇文章主要介紹了基于HTML5的WebSocket的實(shí)例代碼,需要的朋友可以參考下2018-08-15



