Vue 自定义消息通知组件

前言

        由于业务需求,需要使用一个消息的全局通知组件,项目原来是使用Element上的通知组件,但是到了后面发现Element的通知组件无法满足消息通知的时间性以及可条跳转性准则所以需要自己开发一个消息通知组件,话不多说,先上干货吧。

下面为消息通知组件的使用情况,这个组件设置为可跳转不可跳转两种

可跳转通知(在查看详情中可定义相关方法通过点击去触发,比如说放路由,或者相关URL)

 

 不可跳转通知(纯通知)

 这个是通知组件设计时的vue上的目录结构

 通知组件的调用方法

 组件调用代码

this.$myMsg.notify({
                      title:"通知标题",
                      content: "通知内容",
                      type: 'jumpNotification',
                      time: 0,
                      timeNow:new Date().getTime()
                  });

 界面组件代码

<!--
 * @Descripttion: 通知组件的绘制界面
 * @version: 
 * @Author: 刘延强
 * @Date: 2021-07-26 09:51:32
 * @LastEditors: 刘延强
 * @LastEditTime: 2021-07-28 15:52:07
-->

<template>
  <transition name="slide-fade">
    <div class="my-notify" v-if="notifyFlag">
        <!-- 可跳转通知 -->
      <div class="notify" v-if="type=='jumpNotification'">
          <div class="notice">
            <div><div class="iconmessage"><div class="el-icon-bell icon-xiaoxi"></div></div></div>
             <div class="subject-content">
                <div class="h3">{
   
   {title}}<!-- 消息标题 -->
                </div>
                <div class="content">
                    <div class="left-part">
                    <span class="right">{
   
   { content }}</span><!-- 消息内容 -->
                    </div>
                </div>
             </div>
                    <div class="close" @click="close()">
                      <i class="el-icon-circle-close"/>
                    </div>
          </div>
        <div class="tableTitle"></div>
        <div class="more" @click="clickSet()" >
            <div class="txt" v-time="timeNow"></div>
            <div class="toinfo">
              <span class="txt">查看详情</span>
              <span class="el-icon-arrow-right el-icon--right"/>
            </div>
          </div>
          
      </div>

      <!-- 不跳转的通知 -->
      <div class="notify" v-if="type=='noJumpNotification'">
          <div class="notice">
            <div><div class="iconmessage1"><div class="el-icon-bell icon-xiaoxi"></div></div></div>
             <div class="subject-content">
                <div class="h3">{
   
   {title}}<!-- 消息标题 -->
                </div>
                <div class="content">
                    <div class="left-part">
                    <span class="right">{
   
   { content }}</span><!-- 消息内容 -->
                    </div>
                </div>
             </div>
                    <div class="close" @click="close()">
                    <i class="el-icon-circle-close"/>
                    </div>
          </div>
      </div>
    </div>
  </transition>
</template>
 
<style scoped>

.subject-content{
    margin: 0 0 15px 10px;
}


.left-part {
  width: 260px;
  overflow: hidden;
  display: flex;
  flex-flow: row wrap;
  justify-content: start;
  align-items: center;
}

.iconmessage {
  width: 44px;
  height: 44px;
  background: rgba(125, 191, 243, 1);
  border-radius: 100%;
  margin-top: 7px;
}

.iconmessage1 {
  width: 44px;
  height: 44px;
  background: rgba(125, 191, 243, 1);
  border-radius: 100%;
  margin-top: -17px;
}

.icon-xiaoxi {
  text-align: center;
  line-height: 45px;
  font-size: 26px;
  color: white;
  margin-left: 9px;
}

.notice {
  display: flex;
  flex-flow: row nowrap;
  align-items: center;
  width: calc(100% - 30px);
  padding: 0 15px;
  background: white;
  padding-bottom: 10px;
  border-radius: 5px;
  padding-top: 25px;
  z-index:99999;
}



.close {
    position: absolute;
    right: 5px;
    top: 1px;
    color: #409eff;
    cursor: pointer;
    font-size: 22px;
    font-weight: bold;
}
.tableTitle {
    position: relative;
    margin: 0 auto;
    width: 100%;
    height: 1px;
    background-color: #d4d4d4;
    text-align: center;
    font-size: 16px;
    color: rgba(101, 101, 101, 1);
}

.more {
  display: flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  align-items: center;
  width: calc(100% - 30px);
  padding: 0 15px;
  background: white;
  border-radius: 5px;
}

.txt{
  cursor:pointer;
  font-size: 12px;
  font-family: MicrosoftYaHei;
  color: rgba(169, 169, 169, 1);
  line-height: 16px;
  padding: 20px 0;
}

.info {
  display: flex;
  flex-flow: column nowrap;
  justify-content: center;
  align-items: flex-start;
  position: relative;
  top: 0.66667vw;
  width: calc(100% - 24vw);
}

.toinfo {
  display: flex;
  justify-content: center;
  align-items: center;
}


.slide-fade-leave-active {
  transition: all .2s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to{
  transform: translateX(10px);
  opacity: 0;
}

.my-notify{
  margin: 10px;
  width: 350px;
  z-index: 99999;
}
.notify{
  position: relative;
  width: 350px;
  border-radius: 5px;
  background-color:white;
  box-shadow: -5px 5px 12px 0 rgba(204, 204, 204, .8);
  animation: show cubic-bezier(.18,.89,.32,1.28) .4s;
  /* 图文不可复制CSS */
  -webkit-user-select: none;
  -ms-user-select: none;
  -moz-user-select: none;
  -khtml-user-select: none;
  user-select: none;
}

.notify .tip{
  height: 30px;
  margin-bottom: 5px;
  line-height: 30px;
}

.h3 {
    width: 260px;
    font-family: MicrosoftYaHei;
    color: rgba(169, 169, 169, 1);
    color: #232323;
    font-size: 17px;
    font-weight: 600;
    padding: 0;
}

.notify .tip span{
  line-height: 30px;
  font-size: 17px;
  font-weight: 600;
}
@keyframes show{
  0%{
    right: -350px;
  }
  100%{
    right: 10px;
  }
}
</style>

 界面逻辑JS

/*
 * @Descripttion: 通知组件的相关逻辑
 * @version: 
 * @Author: 刘延强
 * @Date: 2021-07-26 09:52:22
 * @LastEditors: 刘延强
 * @LastEditTime: 2021-07-28 16:16:00
 */

import vue from 'vue'
import myNotify from './myNotify'
import './timeDifference.js'
import Utils from './util';
 
// 创建vue组件实例
const notify = vue.extend(myNotify);
 
//添加通知节点(用来存放通知的元素)
let notifyWrap = document.createElement('div');
notifyWrap.className = "notify-wrap"
// notifyWrap.style = "position: fixed; right: 0px; top: 90px; transition-duration: .5s;"
notifyWrap.style = "position: fixed;right: 0px; bottom: 0px; transition-duration: .5s;"
document.body.appendChild(notifyWrap);
 
let myMsg = {
  /**
   * 通知框
   * @title 提示标题
   * @content 提示内容;
   * @type 提示框类型,parameter: jumpNotification,noJumpNotification
   * @time 显示时长
   * @timeNow 弹窗出现的时间
   */
  notify: ({
    title,
    timeNow,
    content, 
    type, 
    time = 2000,
  }) => {
    //创建一个存放通知的div
    const notifyDom = new notify({
      el: document.createElement('div'),
      data () {
        return {
          title:title, //文本标题
          timeNow:timeNow,//弹窗出现的时间
          notifyFlag: true, // 是否显示
          time: time,//取消按钮是否显示
          content: content, // 文本内容
          type: type, // 类型
          timer: '',
          timeFlag: false,
        }
      },
      watch:{
        timeFlag(){
          if(this.timeFlag){
            this.notifyFlag = false;
            window.clearTimeout(this.timer); 
          }
        }
      },
      created(){
        this.timer = setTimeout(() => { 
          if(this.time!=0){
            this.timeFlag = true;
          }
        }, this.time);
         
      },

      //销毁一个通知实例
      beforeDestroy(){
        window.clearTimeout(this.timer); 
      },
      methods: {
        //关闭通知消息
        close() {
            window.clearTimeout(this.timer); 
            this.notifyFlag = false;
          },

        //点击查看详情的方法
        clickSet() {
            Utils.$emit('Brainstorm','msg')
            this.close();
        }
          
      }
    })

    //往notifyWrap里面添加通知
    // notifyWrap.appendChild(notifyDom.$el);  //这个的意思是把div元素节点添加到body元素节点中成为其子节点,但是其后面添加的新节点放在body的现有子节点的最后
    notifyWrap.insertBefore(notifyDom.$el, document.body.lastElementChild.firstChild);//这个的意思是把div元素节点添加到body元素节点中成为其子节点,但是放在body的现有子节点的最前面

  }
}
 
//注册
function register(){
  vue.prototype.$myMsg = myMsg
}
 
export default {
  myMsg,
  register
}

通知时间JS

/*
 * @Descripttion: 消息推送的时间变化组件
 * @version: 
 * @Author: 刘延强
 * @Date: 2021-07-23 18:29:19
 * @LastEditors: 刘延强
 * @LastEditTime: 2021-07-23 19:29:52
 */

import Vue from 'vue'

/**
 * 实时时间转换指令,大于一个月则返回具体的年月日
 * @param { string } timeStamp - 时间 格式:年-月-日 时:分:秒 或 时间戳
 * @returns { string }
 */

function getFormatTime(timeStamp){
	var dateTime = new Date(timeStamp) // 将传进来的字符串或者毫秒转为标准时间
    var year = dateTime.getFullYear()
    var month = dateTime.getMonth() + 1
    var day = dateTime.getDate()
    var hour = dateTime.getHours()
    var minute = dateTime.getMinutes()
    // var second = dateTime.getSeconds()
    var millisecond = dateTime.getTime() // 将当前编辑的时间转换为毫秒
    var now = new Date() // 获取本机当前的时间
    var nowNew = now.getTime() // 将本机的时间转换为毫秒
    var milliseconds = 0
    var timeSpanStr
    milliseconds = nowNew - millisecond
    if (milliseconds <= 1000 * 60 * 1) { // 小于一分钟展示为刚刚
        timeSpanStr = '刚刚'
    } else if (1000 * 60 * 1 < milliseconds && milliseconds <= 1000 * 60 * 60) { // 大于一分钟小于一小时展示为分钟
        timeSpanStr = Math.round((milliseconds / (1000 * 60))) + '分钟前'
    } else if (1000 * 60 * 60 * 1 < milliseconds && milliseconds <= 1000 * 60 * 60 * 24) { // 大于一小时小于一天展示为小时
        timeSpanStr = Math.round(milliseconds / (1000 * 60 * 60)) + '小时前'
    } else if (1000 * 60 * 60 * 24 < milliseconds && milliseconds <= 1000 * 60 * 60 * 24 * 15) { // 大于一天小于十五天展示位天
        timeSpanStr = Math.round(milliseconds / (1000 * 60 * 60 * 24)) + '天前'
    } else if (milliseconds > 1000 * 60 * 60 * 24 * 15 && year === now.getFullYear()) {
        timeSpanStr = month + '-' + day + ' ' + hour + ':' + minute
    } else {
        timeSpanStr = year + '-' + month + '-' + day + ' ' + hour + ':' + minute
    }
    return timeSpanStr
	}

Vue.directive('time', {
	bind: function(el, binding){
		el.innerHTML = getFormatTime(binding.value);
		//每隔一分钟更新一次
		el.__timeout__ = setInterval(function(){
			el.innerHTML = getFormatTime(binding.value);
		}, 60000);
	},
	unbind: function(el){
		clearInterval(el.__timeout__);
		delete el.__timeout__;
	}
});

查看详情的调用方法的公共文件

/*
 * @Descripttion: 跨页面方法调用方法的公共文件
 * @version: 
 * @Author: 刘延强
 * @Date: 2021-07-26 17:55:56
 * @LastEditors: 刘延强
 * @LastEditTime: 2021-07-26 20:01:49
 */

import Vue from 'vue'
export default new Vue

被远程跨界面调用的方法

//被远程跨界面调用的方法
    //@Brainstorm 头脑风暴跳转调用  
    var that = this;
    Utils.$on('Brainstorm', function (msg) {
      that.jumpPage();
    })

最后需要去main.js注册才可以全局使用这个组件

//通知消息
import message from "@/components/myMsg/index"
Vue.use(message.register);

写的不是很好,望大佬们指正!

猜你喜欢

转载自blog.csdn.net/weixin_44684272/article/details/119181560
今日推荐