一、功能需求
1.这是我在后台管理项目中使用到的,主要的作用是搞一个消息提醒的功能。
2.主要有右上角的提示和有下角的消息弹框。
3.主要实现的功能是如果用户有未读的消息,那么首次登录就弹框,如果用户关闭了页面,那么再次刷新页面的时候,也不再弹框,意思就是一个账户没有退出之前,也没有实时消息推送的时候,只弹一次框。
4.如果用户点击了未读消息,那么就会将此条消息置位历史(已读)。
页面展示:
二、页面代码
备注:我的是后台管理系统(用的是vue-element-admin),第一次写websocket,所以我写在了src->layout->AppMain.vue文件下面:
<template><section class="app-main"><Message-remind :message-list="messageList" /><transition name="fade-transform" mode="out-in"><keep-alive :include="cachedViews"><router-view :key="key" /></keep-alive></transition></section>
</template><script>import MessageRemind from '@/components/MessageRemind/index.vue'import { getToken, getSid } from "@/utils/auth"; // get token from cookieexport default {name: 'AppMain',components: {MessageRemind},watch: {'$store.state.user': {handler: function (newValue, oldValue) {// 如果没有token,则表明退出了登录if (!newValue.token) {this.closeWebSocket();}},immediate: true,deep: true}},data() {return {// socket参数socket: null,timeout: 60 * 1000, // 45秒一次心跳timeoutObj: null, // 心跳心跳倒计时serverTimeoutObj: null, // 心跳倒计时timeoutnum: null, // 断开 重连倒计时lockReconnect: false, // 防止websocket: null,messageList: {}};},created() {const hasToken = getToken();const sid = getSid();if (hasToken) {this.initWebSocket(hasToken, sid)}},computed: {cachedViews() {return this.$store.state.tagsView.cachedViews},key() {return this.$route.path}},mounted() {// console.log(this.$store.state.tagsView.cachedViews)},methods: {initWebSocket(token, sid) {// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于httpsthis.websocket = new WebSocket(process.env.VUE_APP_WEB_SOCKET_BASE_API + '?uiticket=' + token + '&sid=' + sid);this.websocket.onopen = this.websocketonopen;this.websocket.onerror = this.websocketonerror;this.websocket.onmessage = this.setOnmessageMessage;this.websocket.onclose = this.websocketclose;// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。// window.onbeforeunload = that.onbeforeunload},start() {//清除延时器this.timeoutObj && clearTimeout(this.timeoutObj);this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);this.timeoutObj = setTimeout(() => {if (this.websocket && this.websocket.readyState == 1) {this.websocket.send('{"messageType": 99}');//发送消息,服务端返回信息,即表示连接良好,可以在socket的onmessage事件重置心跳机制函数} else {this.reconnect();}//定义一个延时器等待服务器响应,若超时,则关闭连接,重新请求server建立socket连接this.serverTimeoutObj = setTimeout(() => {this.websocket.close();}, this.timeout)}, this.timeout)},reset() { // 重置心跳// 清除时间clearTimeout(this.timeoutObj);clearTimeout(this.serverTimeoutObj);// 重启心跳this.start();},// 重新连接reconnect() {if (this.lockReconnect) returnthis.lockReconnect = true;//没连接上会一直重连,设置延迟避免请求过多this.timeoutnum && clearTimeout(this.timeoutnum);this.timeoutnum = setTimeout(() => {this.initWebSocket();this.lockReconnect = false;}, 5000)},async setOnmessageMessage(event) {this.messageList = JSON.parse(event.data)if (this.messageList.data.messageType === 999) {this.websocket.send('{"messageType": 99}');}this.$store.dispatch('user/steMessageMenu', this.messageList)this.reset();// 自定义全局监听事件window.dispatchEvent(new CustomEvent('onmessageWS', {detail: {data: event.data}}))//发现消息进入 开始处理前端触发逻辑// if (event.data === 'success' || event.data === 'heartBath') return},websocketonopen(e) {// console.log('onopen', {e});//开启心跳this.start();console.log("WebSocket连接成功!!!" + new Date() + "----" + this.websocket.readyState);},websocketonerror(e) {// console.log('websocketonerror', {e});console.log("WebSocket连接发生错误" + e);},websocketclose(e) {this.websocket.close();clearTimeout(this.timeoutObj);clearTimeout(this.serverTimeoutObj);console.log("WebSocket连接关闭");},websocketsend(messsage) {this.websocket.send(messsage)},closeWebSocket() { // 关闭websocketthis.websocket.close()},},}
</script><style lang="scss" scoped>@import "~@/styles/global-height.scss";.app-main {/* 50= navbar 50 */// min-height: calc(100vh - #{$navbar+'px'});width: 100%;position: relative;overflow: hidden;display: flex;flex-direction: column;flex: 1;}.fixed-header+.app-main {padding-top: #{$navbar+'px'};}.hasTagsView {.app-main {// min-height: calc(100vh - #{$appMain+'px'});}.fixed-header+.app-main {padding-top: 90px;}}.copy {text-align: center;height: 30px;line-height: 30px;font-size: 13px;color: #666;background: #fff;width: 100%;box-shadow: 0 0 10px #dfe4ed;}
</style><style lang="scss">// fix css style bug in open el-dialog.el-popup-parent--hidden {.fixed-header {padding-right: 15px;}}
</style>