vue elementUI实现消息通知功能

本文介绍了如何在Vue项目中利用ElementUI实现消息通知功能,并结合WebSocket保持实时通信。登录成功后,建立WebSocket连接并采用心跳机制维持连接状态。根据用户权限决定关闭或保持连接。当收到消息时,创建notify并存储,用户点击详情视为已读,否则5秒后自动关闭视为未读。在notify的onClose事件中,通过isRead字段区分手动与自动关闭,并更新未读消息计数。
  1. 登录成功后建立WebSocket链接,使用心跳机制保持连接状态
  2. 后端根据用户权限选择关闭或保持连接状态
  3. 收到消息时创建一个notify并以id作为key值保存到通知对象
  4. notify自动消失前点击详情按钮视为消息已读
  5. 5秒后自动消失视为未读,关闭事件中设置未读数量加1,删除对象中相应notify实例

 具体实现如下:

import { createNamespacedHelpers } from 'vuex'
const { mapState, mapActions, mapMutations } = createNamespacedHelpers(
  'message'
)
export default {
    data() {
        return {
            notifyObj: {},
        }
    },
   // 监听消息对象
   watch: {
    notice: {
      handler(newValue) {
        if (newValue.createTime) {
          this.openNotify(newValue)
          const dateTime = moment().format('YYYY-MM-DD HH:mm:ss')
          this.$iNotify({
            title: `消息提示`,
            body: newValue.messageContent + '\r\n' + dateTime,
            account: newValue.account,
            type: newValue.type,
            uniqueid: newValue.uniqueid
          })
        }
      }
    },
    deep: true,
    immediate: true
  },
    // 弹出新消息通知
    openNotify(mess) {
      const h = this.$createElement
      const notify = this.$notify({
        duration: 3000,
        customClass: 'message-notify',
        onClose: () => {
          this.closeNotify(mess)
        },
        message: h(
          'div',
          {
            class: ['notice-con']
          },
          [
            h(
              'p',
              {
                class: ['notice-title']
              },
              [
                h('span', {
                  class: ['el-icon-warning', 'notice-icon']
                }),
                '消息提示'
              ]
            ),
            h(
              'p',
              {
                class: ['notice-text']
              },
              mess.messageContent
            ),
            h(
              'el-button',
              {
                class: ['fr'],
                attrs: {
                  type: 'primary',
                  size: 'mini'
                },
                on: {
                  click: () => {
                    mess.isRead = 1
                    this.toDetail(mess)
                  }
                }
              },
              '督导'
            )
          ]
        )
      })
      this.notifyObj[mess.id] = notify
    },
// 关闭消息弹窗
closeNotify(mess) {
      delete this.notifyObj[mess.id]
      if (!mess.isRead) {
        this.messageCount++
      }
      if (this.show) {
        this.$refs.messagePop.list.unshift(mess)
      }
    },
}

notify的onClose 在5秒自动关闭和手动关闭的情况下都会触发,但要区分两种情况,需要在弹窗内部的click事件中为对象添加标识,这是使用的isRead, 1表示手动点的关闭,0表示5秒后自动关闭,this.notifyObj用来存储notify实例,关闭时通过id进行删除对应实例

import store from '@/store/'
import * as types from '@/store/types'
import { Message } from 'element-ui'
import { socketUrl, id } from './config'

class Ws {
  constructor(options = {}) {
    this.account = options.account
    this.token = options.token
    this.url = `${socketUrl}/message/${this.account}/${id}`
    this.timer = null
    this.closeTimer = null
    this.time = 30 * 1000
    this.isHeart = false
    this.ws = null
    this.isMyClose = false

    this.create()
  }
  create() {
    this.ws = new WebSocket(this.url)
    this.ws.onclose = this.onclose
    this.ws.onerror = this.onerror
    this.ws.onopen = this.onopen
    this.ws.onmessage = this.onmessage
  }
  close = () => {
    this.isMyClose = true
    this.ws.close()
  }
  send = (obj = {}) => {
    this.ws.send(JSON.stringify(obj))
  }
  heartCheck = () => {
    clearTimeout(this.timer)
    this.timer = setInterval(() => {
      if (this.isHeart) {
        this.send({ type: 1, data: { heartCheck: true } })
        this.isHeart = false
      } else {
        this.create()
      }
    }, this.time)
  }
  onclose = (e) => {
    if (e.code === 3000 || e.code === 3001) {
      console.log(e, '没有消息提醒权限')
      clearInterval(this.timer)
    } else if (!this.isMyClose) {
      clearTimeout(this.closeTimer)
      this.closeTimer = setTimeout(() => {
        this.create()
      }, 5 * 1000)
    } else {
      clearInterval(this.timer)
      if (e.reason) {
        Message.error(e.reason)
      }
    }
  }
  onerror = () => {}
  onopen = () => {
    this.isHeart = true
    this.send({ type: 0, data: this.token })
    this.heartCheck()
  }
  onmessage = (e) => {
    const data = e.data
    try {
      const obj = JSON.parse(data)
      if (obj.heartCheck) {
        this.isHeart = true
        return
      }

      // 接收消息
      store.commit(`message/${types.SET_NOTICE}`, obj)
    } catch (error) {
      this.isHeart = true
      console.log(error)
    }
  }
}

export default Ws
import Ws from '@/utils/WebsocketMessage'
import * as types from '@/store/types'
// import {  } from '@/api/message'
import store from '../index'
const state = {
  ws: null,
  notice: {}
}
const mutations = {
  [types.SET_WEBSCOKET_MESSAGE](state, ws) {
    state.ws = ws
  },
  [types.CLOST_WEBSCOKET_MESSAGE](state) {
    state.ws = null
    state.notice = {}
  },
  [types.SET_NOTICE](state, data) {
    state.notice = { ...data }
  }
}
const actions = {
  // 设置websocket
  [types.SET_WEBSCOKET_MESSAGE]({ commit }) {
    const ws = new Ws({
      account: store.state.user.detail.account,
      id: store.state.user.detail.id,
      token: store.state.user.token
    })
    commit(types.SET_WEBSCOKET_MESSAGE, ws)
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值