Vue 项目中使用WebSocket 消息推送

news2025/1/9 16:56:33

一、功能需求

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 cookie
  export 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等同于https
        this.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) return
        this.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() { // 关闭websocket
        this.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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/707360.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手把手教学使用宝塔面板部署前后端分离项目(全面详细)

前言&#xff1a;平日里我们的前后端项目基本上都是通过linux系统提供的dos命令去部署&#xff0c;有没有一种更简单的方式去部署我们自己的项目呢&#xff0c;答案是有的&#xff0c;本篇博客就是手把手教学如何通过一个可视化的页面去部署我们自己开发的前后端分离项目。 目录…

【Java项目】解决请求路径上明文ID传输导致可能被攻击的方法

文章目录 问题思路解决 问题 这个问题是我公司的一个小业务问题&#xff0c;问题来源于我们发送请求的时候&#xff0c;请求路径上携带的是明文&#xff0c;比如http://xxx/xxx/id12345&#xff0c;那么别有用心的人就可能会推测出id的生成策略&#xff0c;导致遍历id&#xf…

【需求实现】Tensorflow2的曲线拟合(一):数据集分割

神经网络中输入多少数据就输出多少数据的情况如何实现 导读数据集长什么样&#xff1f;怎么分割数据集&#xff1f;时间窗口分析模板我知道你很急&#xff0c;但你先别急 换个思路 导读 在实习的过程中遇到了这样一种需求&#xff1a;给定一条序列&#xff0c;并另外给定一条期…

vue如何封装一个上传多张图片的组件

上传图片不管是后台还是前端小程序&#xff0c;上传图片都是一个比不可少的功能有时候需要好几个页面都要上传图片&#xff0c;每个页面都写一个非常不方便&#xff0c;这时候就没有封装起来用的方便。跟上我的步伐带你了解如何封装 首先&#xff1a;创建一个文件夹在component…

【FFmpeg实战】过滤器 ---- h264_mp4toannexb

原文地址&#xff1a;https://www.cnblogs.com/vczf/p/13818609.html H264有两种封装方式&#xff1a;字节流AnnexB格式 AVCC格式。 1. AnnexB格式 ---- 用于实时播放 开始前缀&#xff08;00000001或000001&#xff09;&#xff0b;NALU数据  绝大部分编码器的默认输出格式…

leetcode题目1481. 不同整数的最少数目

题目 不同整数的最少数目 给你一个整数数组 arr 和一个整数 k 。现需要从数组中恰好移除 k 个元素&#xff0c;请找出移除后数组中不同整数的最少数目。 示例 1&#xff1a; 输入&#xff1a;arr [5,5,4], k 1 输出&#xff1a;1 解释&#xff1a;移除 1 个 4 &#xff0c…

初识消息队列

消息队列 字面意思就是存放消息的队列(Message Queue 简称MQ)&#xff0c;最简单的消息队列模型包括了三个角色&#xff1a; 消息队列&#xff1a;存储和管理信息&#xff0c;也被称为消息代理生产者&#xff1a;发送消息到消息队列消费者&#xff1a;从消息队列中获取消息并…

基于TensorFlow和Keras的狗猫数据集的分类实验

文章目录 前言一、环境配置1、anaconda安装2、修改jupyter notebook工作目录3、配置TensorFlow、Keras 二、数据集分类1、分类源码2、训练流程 三、模型调整1.图像增强2、网络模型添加dropout层 四、使用VGG19优化提高猫狗图像分类1、构建网络模型2、初始化一个VGG19网络实例3、…

C语言--消失的数字

文章目录 1.法一&#xff1a;映射法2.法二&#xff1a;异或法3.法三&#xff1a;差值法4.法四&#xff1a;排序查找 1.法一&#xff1a;映射法 时间复杂度&#xff1a;O&#xff08;N&#xff09; 空间复杂度&#xff1a;O&#xff08;N&#xff09; #include<stdio.h>…

第4章 信息系统管理

文章目录 4.1.1 管理基础1 层次结构2 系统管理 4.1.2 规划和组织1 规划模型2 组织模型1&#xff09;业务战略&#xff08;竞争力优势模型&#xff1a;差异化、总成本领先、专注 战略&#xff09;2&#xff09;组织机制战略&#xff08;莱维特钻石模型&#xff1a;信息与控制、人…

【C++学习】类和对象 | 再谈构造函数 | 构造函数中的隐式类型转换 | static静态成员

目录 1. 再谈构造函数 2. 构造函数中的隐式类型转换 3. static静态成员 写在最后&#xff1a; 1. 再谈构造函数 我们之前使用构造函数初始化&#xff1a; #include <iostream> using namespace std;class Date { public:Date(int year 2023, int month 7, int da…

arcgis js 通过某一个经纬度 定位报错,并且图标变得很大【已解决】

报错 svg.js:42 Error: attribute transform: Expected number, “…0000,0.02102085,NaN,NaN)”. svg.js:49 Error: attribute x: Expected length, “NaN”. svg.js:49 Error: attribute y: Expected length, “NaN”. 图标特别大&#xff0c;也看不到地图 分析 这个方法中…

智驾“平价”,小鹏G6打特斯拉是认真的

作者|张祥威编辑|德新 “小鹏在辅助驾驶领域不是遥遥领先&#xff0c;而是领先友商 12 - 36 个月。” “希望L4的能力能够在2027年到来&#xff0c;或者更早一点。” “G6的销量肯定要过万&#xff0c;这是最起码的。” G6上市发布期间&#xff0c;小鹏的高管各种喊话。 抛开80…

(嵌入式)STM32G061C8T6、STM32G061C6T6、STM32G061C8U6 64MHz 64KB/32KB 闪存(MCU)

STM32G0 32位微控制器 (MCU) 适合用于消费、工业和家电领域的应用&#xff0c;并可随时用于物联网 (IoT) 解决方案。这些微控制器具有很高的集成度&#xff0c;基于高性能ARM Cortex-M0 32位RISC内核&#xff0c;工作频率高达64MHz。该器件包含内存保护单元 (MPU)、高速嵌入式内…

算法笔记--滑动窗口

力扣209.长度最小子数组 https://leetcode.cn/problems/minimum-size-subarray-sum/ 在这道题中要注意的不仅仅是滑动窗口的问题&#xff0c;更重要的问题是在循环控制中&#xff0c;不恰当的语法使用会导致这道题出现很严重的问题&#xff0c;这导致我做这道题做了很多天&…

亿级数据毫秒级响应?

作为一名深陷在增删改查泥潭中练习时长三年的夹娃练习生&#xff0c;偶尔会因为没有开发任务不知道周报写什么而苦恼。 正愁这周写啥呢&#xff0c;组长过来交代了个跟进第三方公司性能测试报告的工作&#xff0c;我一寻思这活不最好干了吗&#xff0c;正愁不知道周报咋写呢&a…

github上传文件及其问题解决

文章目录 1. github上上传文件夹2. <filename> does not have a commit checked out3. this exceeds GitHubs file size limit of 100.00 MB4. error: src refspec master does not match any 1. github上上传文件夹 首先在github上create a new repository&#xff0c;…

C语言王国探险记之字符串+注释

王国探险记系列 文章目录&#xff08;3&#xff09; 前言 一&#xff0c;什么是字符串呢&#xff1f; 1&#xff0c;那C语言是怎么表示字符串的呢? "hello world.\n" 2&#xff0c;证明字符串的结束标志是一个 \0 的转义字符 3&#xff0c;证明字符串的结束标…

云原生之深入解析Flink on k8s的运行模式与实战操作

一、概述 Flink 核心是一个流式的数据流执行引擎&#xff0c;并且能够基于同一个 Flink 运行时&#xff0c;提供支持流处理和批处理两种类型应用。其针对数据流的分布式计算提供了数据分布&#xff0c;数据通信及容错机制等功能。Flink 官网不同版本的文档flink on k8s 官方文…

linux-2.6.22.6内核网卡驱动框架分析

网络协议分为很多层&#xff0c;而驱动这层对应于实际的物理网卡部分&#xff0c;这也是最底层的部分&#xff0c;以cs89x0.c这个驱动程序为例来分析下网卡驱动程序框架。 正常开发一个驱动程序时&#xff0c;一般都遵循以下几个步骤&#xff1a; 1.分配某个结构体 2.设置该结…