• electron桌面应用webSoket实时弹框提示实现


    一、实现效果:网页端或者移动端进行了审核操作,在电脑右下角提示用户查看。

            1、当有弹框提示的情况时,会弹出如下提示,点击查看自动跳转到当前地址,点击关闭则关闭当前提示窗口;

            2、当有两条及其以上的消息要审核时,弹框的内容会变成如下展示:

    二、实现思路: 

    1、在主进程main.js中创建弹框,并确定弹框的位置;

    2、编写弹框内容和样式;

    3、在登录成功后使用webSoket实时监听消息;

    4、主进程收到消息后触发提示弹框展示;

    三、代码实现:

    1、主进程main.js中:

    1. // main.js
    2. // 监听
    3. ipcMain.on('remindWindow:close', () => {
    4. remindWindow.close()
    5. })
    6. // 判断在弹框关闭前一共收到几次消息
    7. let num = 1
    8. ipcMain.on('open-remind', (event, task, twrUrl) => {
    9. if (remindWindow) {
    10. num++
    11. remindWindow.webContents.send('show-remind', task, twrUrl, num)
    12. } else {
    13. num = 1
    14. createRemindWindow(task, twrUrl)
    15. }
    16. })
    17. // 创建提示弹出窗
    18. const iconPath = path.join(__dirname, './src/img/icon.png')
    19. function createRemindWindow(task, twrUrl) {
    20. if (remindWindow) remindWindow.close()
    21. remindWindow = new BrowserWindow({
    22. height: 180,
    23. width: 300,
    24. resizable: false,
    25. frame: false,
    26. icon: iconPath,
    27. show: false,
    28. webPreferences: {
    29. nodeIntegration: true,
    30. contextIsolation: false, //关闭上下文隔离的
    31. // preload: path.join(__dirname, './preload.js')
    32. },
    33. })
    34. // 打开控制台
    35. // remindWindow.webContents.openDevTools()
    36. remindWindow.removeMenu()
    37. // 右下角弹出
    38. const size = screen.getPrimaryDisplay().workAreaSize
    39. const { y } = tray.getBounds()
    40. const { height, width } = remindWindow.getBounds()
    41. const yPosition = y - height
    42. remindWindow.setBounds({
    43. x: size.width - width,
    44. y: yPosition,
    45. height,
    46. width,
    47. })
    48. remindWindow.setAlwaysOnTop(true)
    49. remindWindow.loadURL(`file://${__dirname}/src/remind.html`)
    50. remindWindow.show()
    51. // 发消息
    52. remindWindow.webContents.send('show-remind', task, twrUrl)
    53. remindWindow.on('closed', () => {
    54. remindWindow = null
    55. })
    56. }

    2、登录成功后获取实时信息弹框提示;

    1. // login.js
    2. // 获取登录
    3. async function getLogin({ account, password }) {
    4. // do something
    5. if (response.ok) {
    6. // 登录成功后触发webSoket
    7. initWebSocket()
    8. }
    9. }
    10. const heartbeatInterval = 30000 // 心跳检测间隔,单位:毫秒
    11. const reconnectInterval = 3000 // 重连间隔,单位:毫秒
    12. let socket = null
    13. let isReconnecting = false
    14. // 心跳检测
    15. function startHeartbeat() {
    16. setInterval(() => {
    17. if (socket && socket.readyState === WebSocket.OPEN) {
    18. // 发送心跳消息到服务器
    19. socket.send('heartbeat')
    20. }
    21. }, heartbeatInterval)
    22. }
    23. // 获取实时信息弹框提示
    24. function initWebSocket() {
    25. const socUrl = 'ws://xxx/xxx'
    26. socket = new WebSocket(socUrl)
    27. // 监听连接事件
    28. socket.onopen = () => {
    29. console.log('WebSocket连接已建立')
    30. // 启动心跳检测
    31. startHeartbeat()
    32. }
    33. // 监听消息事件
    34. socket.onmessage = event => {
    35. console.log('收到数据:', event)
    36. // 启动心跳检测
    37. startHeartbeat()
    38. if (event.data === 'HeartBeatResp') {
    39. // 心跳响应消息不做处理
    40. return
    41. }
    42. const socketData = JSON.parse(event.data)
    43. // 收到消息后发消息给主进程 socketData:提示信息 | twrUrl.value:跳转地址
    44. if (socketData) {
    45. ipcRenderer.send('open-remind', socketData, twrUrl.value)
    46. }
    47. }
    48. // 监听关闭事件
    49. socket.onclose = event => {
    50. console.log(`websocket连接关闭 code: ${event.code}, reason: ${event.reason}, wasClean: ${event.wasClean}`)
    51. reconnectWebSocket()
    52. }
    53. // 监听错误事件
    54. socket.onerror = event => {
    55. console.log('websocket连接错误')
    56. reconnectWebSocket()
    57. }
    58. }
    59. // websocket重连
    60. function reconnectWebSocket() {
    61. if (!isReconnecting) {
    62. // 连接断开时,触发重连
    63. isReconnecting = true
    64. setTimeout(() => {
    65. initWebSocket()
    66. isReconnecting = false
    67. }, reconnectInterval)
    68. }
    69. }

    3、在src文件夹下新建remind.html实现提示弹框具体内容;

    1. DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8" />
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    7. <title>Documenttitle>
    8. <style>
    9. * {
    10. margin: 0;
    11. padding: 0;
    12. box-sizing: border-box;
    13. }
    14. .custom-toolbar {
    15. display: flex;
    16. justify-content: space-between;
    17. align-items: center;
    18. padding: 10px;
    19. font-weight: bold;
    20. background-color: rgb(236, 233, 233);
    21. }
    22. .custom-toolbar .close-button {
    23. cursor: pointer;
    24. font-size: 20px;
    25. position: relative;
    26. bottom: 1px;
    27. }
    28. .custom-toolbar .title-text {
    29. font-size: 16px;
    30. }
    31. .custom-toolbar .title-text > img {
    32. width: 16px;
    33. height: 16px;
    34. position: relative;
    35. top: 2px;
    36. }
    37. .reminder {
    38. text-align: left;
    39. font-size: 14px;
    40. height: 100px;
    41. padding: 10px;
    42. padding-top: 0;
    43. line-height: 24px;
    44. /* letter-spacing: 1.2px; */
    45. overflow: auto;
    46. }
    47. .close,
    48. .detail-button {
    49. position: absolute;
    50. font-size: 14px;
    51. color: dodgerblue;
    52. bottom: 10px;
    53. cursor: pointer;
    54. z-index: 1;
    55. }
    56. .close {
    57. right: 10px;
    58. }
    59. .detail-button {
    60. right: 50px;
    61. }
    62. .num {
    63. color: dodgerblue;
    64. font-weight: bold;
    65. }
    66. style>
    67. head>
    68. <body>
    69. <div class="custom-toolbar">
    70. <div class="title-text">
    71. <img src="./img/icon.png" alt="" />
    72. xxx小助手
    73. div>
    74. <div class="close-button">×div>
    75. div>
    76. <span class="detail-button">查看span>
    77. <span class="close-button close">关闭span>
    78. <div class="reminder">div>
    79. body>
    80. <script>
    81. const electron = require('electron')
    82. const { ipcRenderer } = electron
    83. const { shell } = require('electron/common')
    84. const reminder = document.querySelector('.reminder')
    85. const closeBtns = document.querySelectorAll('.close-button')
    86. const detailBtn = document.querySelector('.detail-button')
    87. let socketData
    88. let url
    89. ipcRenderer.on('show-remind', (event, task, twrUrl, num) => {
    90. socketData = task
    91. url = twrUrl
    92. if (num) {
    93. reminder.innerHTML = `您有${num}条信息需要处理,请及时登录xxx系统操作。`
    94. } else {
    95. reminder.innerHTML = `${socketData.msgContent}`
    96. }
    97. })
    98. // 关闭
    99. closeBtns.forEach(i => {
    100. i.addEventListener('click', () => {
    101. ipcRenderer.send('remindWindow:close')
    102. })
    103. })
    104. // 查看-点击自动跳转到默认浏览器
    105. detailBtn.addEventListener('click', () => {
    106. shell.openExternal(`http://${url}/xxx/#/xxx`)
    107. })
    108. script>
    109. html>

    4、综上所述,即可完成桌面提示功能。

  • 相关阅读:
    C++笔试题详解+扩展
    通过分页插件获取分页的相关数据
    【LeetCode】674. 最长连续递增序列(简单)——代码随想录算法训练营Day52
    【数据结构】单链表
    网络编程学习笔记❤️
    线程池自义定参数设置及预估
    vue-springboot 前后端传参的形式
    【Pytorch深度学习实战】(6)递归神经网络(RNN)
    zabbix的原理与安装
    Vue:(四)数据代理
  • 原文地址:https://blog.csdn.net/weixin_47978760/article/details/134535393