自定义 Notification 通知提醒框

169 阅读1分钟

自定义 Notification 通知提醒框

通常在开发中Ant Design Vue中的Notification 通知提醒框不满足开发需求,此时就需要自己去封装组件了。本示例适用于vue3项目,当然也可以改成vue2。

一、封装组件

<template>
  <div>
    <!-- <a-button @click="click">告警模拟</a-button> -->
    <!-- 消息主体部分 -->
    <div v-for="item in divList" :key="item">
      <div class="notification-style" :id="item.key">
        <div class="title-content">
          <div>告警标题</div>
          <Icon
            icon="iconoir:voice-error"
            v-if="!soundSwitch"
            @click="soundClick(false, item.key)"
          ></Icon>
          <Icon
            icon="iconoir:voice-ok"
            color="#1890ff"
            v-if="soundSwitch"
            @click="soundClick(true, item.key)"
          ></Icon>
        </div>
        <div
          >&nbsp;&nbsp;&nbsp;&nbsp;6#CLP_Slora变电站3#逆变器于{{
            item.time
          }}存在温度过低问题,请确认</div
        >
        <div class="button-content">
          <a-button class="button-style" type="primary">查看</a-button>
        </div>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
  import { notification } from 'ant-design-vue';
  import { Icon } from '/@/components/Icon';
  import { defineComponent, ref, unref, onMounted, nextTick, onBeforeUnmount } from 'vue';
  import publicFun from '/@/utils/publicFun';
  export default defineComponent({
    name: 'LayoutContent',
    components: { Icon },
    setup() {
      // 音频组件实例化
      const audios = ref<any | HTMLElement>(null);
      // 音频组件显示隐藏
      const audioVisible = ref(false);
      // 音频组件声音开关
      const soundSwitch = ref(true);
      const newKey = ref(new Date().getTime());
      // 消息列表
      const divList = ref([]);
      /*
       * @Author: zxl 2641337277@qq.com
       * @Date: 2022-08-29 11:42:57
       * @LastEditors: zxl 2641337277@qq.com
       * @LastEditTime: 2022-08-29 13:53:04
       * @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
       * @Description1: 音频组件的播放
       */
      const startPlay = () => {
        console.log('audios', audios.value.play());
        audios.value.currentTime = 0; //从头开始播放提示音
        audios.value.play(); //播放
      };
      /*
       * @Author: zxl 2641337277@qq.com
       * @Date: 2022-08-29 11:42:57
       * @LastEditors: zxl 2641337277@qq.com
       * @LastEditTime: 2022-08-29 13:53:04
       * @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
       * @Description1: 声音图标的点击播放与暂停
       */
      const soundClick = (e, key) => {
        soundSwitch.value = !e;
        // 获取当前告警实例
        const box = document.getElementById(key + '1');
        if (!e) {
          box.play(); //播放
        } else {
          box.pause(); //暂停
        }
        // console.log('audios', audios.value.play());
        // audios.value.currentTime = 0; //从头开始播放提示音
        // audios.value.play(); //播放
      };
      /*
       * @Author: zxl 2641337277@qq.com
       * @Date: 2022-08-29 11:42:57
       * @LastEditors: zxl 2641337277@qq.com
       * @LastEditTime: 2022-08-29 13:53:04
       * @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
       * @Description: 模拟webstockt实时推送
       */
      // setInterval(() => {
      //   click();
      // }, 6000);
      /*
       * @Author: zxl 2641337277@qq.com
       * @Date: 2022-08-29 11:42:57
       * @LastEditors: zxl 2641337277@qq.com
       * @LastEditTime: 2022-08-29 13:53:04
       * @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
       * @Description: 模拟webstockt推送后事件
       */
      const click = () => {
        // startPlay()
        let nowTime = new Date().getTime();
        let topIndex = divList.value.length * 130;
        let nowTimeStr = publicFun.getStandardTime(new Date());
        divList.value.push({ key: nowTime, label: '', time: nowTimeStr });
        // 生成一个audio元素
        var audio = document.createElement('audio');
        audio.id = nowTime + '1';
        audio.controls = false;
        var start=0
        var times=3
        audio.addEventListener('ended',()=>{
          audio.play()
          start++
          start==times&&audio.pause()
        });
        audio.autoplay = true;
        audio.src = '/@/assets/audio/police.mp3';

        nextTick(() => {
          const box = document.getElementById(nowTime);
          box.style.top = topIndex + 'px';
        });
      };
      /*
       * @Author: zxl 2641337277@qq.com
       * @Date: 2022-08-29 11:42:57
       * @LastEditors: zxl 2641337277@qq.com
       * @LastEditTime: 2022-08-29 13:53:04
       * @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
       * @Description1: 声音播放完成后事件
       */
      const palyFunction = (audio) => {
        audio.autoplay = true;
        for (let i = 0; i < 4; i++) {}
        console.log('声音播放完成后事件声音播放完成后事件');
      };
      /*
       * @Author: zxl 2641337277@qq.com
       * @Date: 2022-08-29 11:42:57
       * @LastEditors: zxl 2641337277@qq.com
       * @LastEditTime: 2022-08-29 13:53:04
       * @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
       * @Description: setInterval实时循环消息列表,改变列表状态
       */
      const interval = setInterval(() => {
        if (divList.value.length > 0) {
          let list = [];
          divList.value.forEach((item, index) => {
            let implement = true;
            if (document.getElementById(item.key)) {
              // 默认4秒时改变div样式
              if (new Date().getTime() - item.key >= 4000) {
                const box = document.getElementById(item.key);
                box.className = 'notification-styles';
              }
              // 默认进行0.2秒class动画
              if (new Date().getTime() - item.key >= 4200) {
                // 删除div
                document.getElementById(item.key)?.remove();
                document.getElementById(item.key + '1')?.remove();
                // 改变状态
                implement = false;
              }
              if (implement) {
                let topIndex = index * 130;
                const box = document.getElementById(item.key);
                box.style.top = topIndex + 'px';
                list.push(item);
              }
            }
          });
          divList.value = list;
        }
      }, 200);
      onBeforeUnmount(() => {
        clearInterval(interval);
        if (divList.value.length > 0) {
          divList.value.forEach((item) => {
            document.getElementById(item.key)?.remove();
            document.getElementById(item.key + '1')?.remove();
          });
        }
      });
      return {
        audios,
        newKey,
        audioVisible,
        soundSwitch,
        click,
        divList,
        soundClick,
      };
    },
  });
</script>
<style lang="less">
  @prefix-cls: ~'@{namespace}-layout-content';

  .@{prefix-cls} {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;

    &.fixed {
      width: 1200px;
      margin: 0 auto;
    }

    &-loading {
      position: absolute;
      top: 200px;
      z-index: @page-loading-z-index;
    }
  }
  .notification-style {
    width: 384px;
    height: 116px;
    max-width: calc(100vw - 24px * 2);
    margin-left: auto;
    position: absolute;
    top: 0px;
    right: 24px;
    z-index: 10;
    margin-bottom: 16px;
    padding: 16px 24px;
    overflow: hidden;
    // line-height: 1.5;
    word-wrap: break-word;
    background: #fff;
    border-radius: 2px;
    box-shadow: 0 3px 6px -4px rgb(0 0 0 / 12%), 0 6px 16px 0 rgb(0 0 0 / 8%),
      0 9px 28px 8px rgb(0 0 0 / 5%);
    animation: myfirst 0.2s;
  }
  @keyframes myfirst {
    0% {
      right: 0px;
    }
    25% {
      right: 6px;
    }
    50% {
      right: 12px;
    }
    75% {
      right: 18px;
    }
    100% {
      right: 24px;
    }
  }
  .notification-styles {
    width: 384px;
    height: 116px;
    position: absolute;
    top: 0px;
    right: 20px;
    z-index: 10;
    margin-bottom: 16px;
    padding: 16px 24px;
    overflow: hidden;
    // line-height: 1.5;
    background: #fff;
    border-radius: 2px;
    box-shadow: 0 4px 12px #00000026;
    animation: myfirsts 0.2s;
  }
  @keyframes myfirsts {
    0% {
      right: 24px;
    }
    25% {
      right: 18px;
    }
    50% {
      right: 12px;
    }
    75% {
      right: 6px;
    }
    100% {
      right: 0px;
    }
  }
  .title-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  .button-content {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    .button-style {
      display: flex;
      justify-content: flex-end;
      align-items: center;
      height: 26px;
    }
  }
</style>

其中“告警模拟”按钮是模拟当系统有告警信息时的操作,setInterval是模拟webstockt推送后事件,具有声音的播放暂停功能,并设置有循环播放次数。

public.getStandardTime方法为:

  /*
  * @Author: zxl 2641337277@qq.com
  * @Date: 2022-08-29 11:42:57
  * @LastEditors: zxl 2641337277@qq.com
  * @LastEditTime: 2022-08-29 13:53:04
  * @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
  * @Description1: 1661756385019时间戳转日期字符串
  * @Description2: Tue May 15 2018 00:00:00 GMT+0800 (中国标准时间)转日期字符串
  * @Description3: 传值为空则获取今日日期字符串
  */
  // 传参分三种
  // 1.传1661756385019时间戳,转日期字符串
  // 2.传Tue May 15 2018 00:00:00 GMT+0800 (中国标准时间),转日期字符串
  // 3.传值为空,则获取今日日期字符串
  getStandardTime(str) {
    var date;
    if (Number(str) > 0) {
      date = new Date(Number(str));
    } else if (str) {
      date = new Date(str);
    } else {
      date = new Date();
    }
    let y = date.getFullYear()
    let M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
    let D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
    let h = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
    let m = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
    let s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
    return y + '-' + M + '-' + D + ' ' + h + ':' + m + ':' + s
  },

二、引入组件

因告警时系统内告警,所以放在layout里面引入较好。

import Notification from '/@/layouts/default/notification/index.vue';
  
components: { PageLayout,Notification },

<template>
  <div>
    <PageLayout />
    <Notification></Notification>
  </div>
</template>

三、效果

截屏2022-11-03 17.32.10.png