Vue custom plug-in--notification box in the upper right corner, which can be automatically closed when the task polling ends

foreword

Recently, I am working on a vue-based cloud console project, which includes many functions such as creating hosts and creating cloud disks, but it takes time to create, and a message notification window that is being created must be displayed to inform customers, and at the same time follow the task The notification window displays success or failure, and can be automatically hidden or manually closed.
There is a Notification notification plug-in in elementui, but there are many places that do not meet my needs, so I consulted the information and packaged one myself.

Business logic

Summarize the business logic: Take the creation of a cloud disk as an example. When the form input is completed and click Create, a request will be sent to the background, and the interface will return whether the operation is successful and the taskId list after the success. At this time, a pop-up window appears in the upper right corner, and There is a loading effect. Next, I will use the taskId to poll every 2 seconds until the result is that the task succeeds or fails. After the polling ends, a pop-up window displays the polling result.
The returned data format after clicking create:

{
    
    
	data:{
    
    
		tasks:[
			{
    
    uuid:'xxxx',name:'创建xx云盘'},
			{
    
    uuid:'xxxx',name:'加载xx云盘'},
		]
	}
}

The return data format of the polling task:

{
    
    
	data:{
    
    
		message:'任务进行中',status:2
	}
}

The effect is as follows:

Task in progress:
insert image description here
Task succeeded:
insert image description here
Task failed:
insert image description here

accomplish

File Directory

insert image description here

the code

1、notify.vue

Several types of pop-up windows are defined here, and transition is used to transition, and the method of manually closing point x is defined.

<template>
  <transition name="slide-fade">
    <div class="my-notify" :name="name" v-if="notifyFlag">
      <span class="close" @click="close"> X </span>  
      <div class="notify success" v-if="type=='success'">
        <img src="../../assets/img/common/success.gif" alt="">
        <div class="content"> {
    
    {
    
    message}}</div>
      </div>
      <div class="notify loading" v-else-if="type=='loading'">
        <img src="../../assets/img/common/loading.gif" alt="">
        <div class="content">{
    
    {
    
    message}}</div>
      </div>
      <div class="notify error" v-else-if="type=='error'">
        <img src="../../assets/img/common/error.png" alt="">
        <div class="content">{
    
    {
    
    message}}</div>
      </div>
      <div class="notify warning" v-else-if="type=='warning'">
        <img src="../../assets/img/common/error.png" alt="">
        <div class="content">{
    
    {
    
    message}}</div>
      </div>
    </div>
  </transition>
</template>

<script>


export default {
    
    
  name: 'vue-notify',
  data() {
    
    
    return {
    
    
      notifyFlag:false,
      type:'loading'
    };
  },
  methods:{
    
    
      close(){
    
    
        this.notifyFlag = false;
      }
  }
  
  
};
</script>

<style>
.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;
  background-color: #f2f5fc;
  border: 1px solid #c4d5ff;
  padding: 9px 10px;
  border-radius:3px;
  margin-top:10px;
  position:relative;  
  margin-right: 19px;
}
.my-notify:hover{
    
    
  border-color:#a9c1fb;  
}
.my-notify .close{
    
    
      position: absolute;
      left:325px;top:7px;
      font-size: 14px;
      z-index: 100;
      cursor: pointer;
      color:#c7c4c4;
  }
  .my-notify .close:hover{
    
    
    color:#aaa;
  }
.notify{
    
    
  position: relative;
  right: 10px;
  padding-left: 10px;
  width: 320px;
  border-radius: 4px;
  background-color:#f2f5fc;    
}
.notify img{
    
    
  display: inline-block;    
  /* vertical-align: text-top; */
  width: 20px;
  margin-right: 7px;
}
.notify .content{
    
    
  width: 270px;
  font-size: 14px;
  vertical-align: top;
  display: inline-block;
}
@keyframes show{
    
    
  0%{
    
    
    right: -350px;
  }
  100%{
    
    
    right: 0;
  }
}

</style>

2、index.js

import vue from 'vue'
import myNotify from './notify.vue'
 
// 创建vue组件实例
const notify = vue.extend(myNotify);

//声明构造函数变量
let func={
    
    };

//添加通知节点(用来存放通知的元素)
let notifyWrap = document.createElement('div');
notifyWrap.className = "notify-wrap"
notifyWrap.style = "position: fixed; right: 0px; top: 65px; transition-duration: .5s;"
document.body.appendChild(notifyWrap);

let NotifyMessage = (options) => {
    
    

  let {
    
    name,message,type} = options;
  
    func['instance'+options.name] = new notify();
    func['instance'+options.name].vm = func['instance'+options.name].$mount();
    //往notifyWrap里面添加通知
    notifyWrap.appendChild(func['instance'+options.name].vm.$el);
    
    func['instance'+options.name].name = name;
    func['instance'+options.name].message = message;
    func['instance'+options.name].type = type;

    func['instance'+options.name].notifyFlag = true;

}
//关闭
NotifyMessage.close = (options) => {
    
    
  let {
    
    name} = options;

  func['instance'+options.name].notifyFlag = false
}
//当成功或者失败时候修改内容和type
NotifyMessage.modify = (options) => {
    
    
  if(typeof options === "object"){
    
    
    let {
    
    name,message,type} = options;
    func['instance'+options.name].message = message;
    func['instance'+options.name].type = type;
  }else{
    
    
    return
  }
}
NotifyMessage.install = (vue) => {
    
    
  vue.prototype.$notifyMessage = NotifyMessage;
}
 
export default NotifyMessage;

3. Register in main.js

import NotifyMessage from '@/plugin/notify/index' 
Vue.use(NotifyMessage)

At this time, it can be used in the page. The usage is

NotifyMessage({
    
    
      name:"xxx",
      message:task.name,
      type:'loading'
    })
    
NotifyMessage.modify({
    
     //修改
      name:"xxx",
      message:task.name,
      type:'success'
    })
    
NotifyMessage.close({
    
    name:'xxx'})//关闭

Because this project needs to poll the task results every 2s to automatically close, so further packaging is carried out.

4、pollingTask.js

import * as commonApi from "@/api/common";
import  NotifyMessage  from '@/plugin/notify/index'

export default function checkTask(options){
    
    
    let task = options;
    NotifyMessage({
    
    
      name:"notify"+task.uuid,
      message:task.name,
      type:'loading'
    })
    let taskId = task.uuid;

    return new Promise((resolve, reject) => {
    
    

      window['diskTimer'+taskId] = window.setInterval(() => {
    
    
        commonApi.checkTask({
    
    uuid:taskId}).then(res => {
    
    
          if (res.code == 200) {
    
    
            if(res.data.status == 1){
    
    //1.进行中 
              return;
            }else if(res.data.status == 2){
    
    //2.成功
              window.clearInterval(window['diskTimer'+taskId]);//清除定时器
              NotifyMessage.modify({
    
    
                name:"notify"+taskId,
                message:task.name,
                type:'success'
              })
              setTimeout(()=>{
    
    
                NotifyMessage.close({
    
    name:'notify'+taskId});//关闭notice
              },2000)
              resolve('任务成功');
            }else{
    
    //3.失败
              window.clearInterval(window['diskTimer'+taskId]);//清除定时器
              NotifyMessage.modify({
    
    
                name:"notify"+taskId,
                message:res.data.message,
                type:'error'
              })
              //任务失败可以选择保持弹窗不关闭,如果要自动关闭则解开代码
              // setTimeout(()=>{
    
    
              //   NotifyMessage.close({name:'notify'+taskId});
              // },3000)
              reject('任务失败');
            }
          } else {
    
    
            window.clearInterval(window['diskTimer'+taskId]);
            NotifyMessage.modify({
    
    
              name:"notify"+taskId,
              message:task.name+'失败',
              type:'error'
            })
            setTimeout(()=>{
    
    
              NotifyMessage.close({
    
    name:'notify'+taskId});
            },3000)
            this.$message({
    
    
              type: "error",
              message: res.msg
            });
            reject('任务失败');
          }
        })
        .catch(err => {
    
    
          console.log(err);
          reject('任务失败');
        });
      }, 2000);
    })
  }

A periodic timer is used here to call the interface every 2s to see if the task is completed. Because the page is automatically refreshed or further operations are performed after the task is completed, a new promise instance is created here to wait for the task to complete, and then perform other operations.

5. Register again in main.js

//轮询操作任务是否完成
import checkTask from '@/utils/pollingTask';
Vue.prototype.$checkTask=checkTask;

6. Usage in the page

// param = {uuid:'xxxxx',name:'创建xx云盘',}
this.$checkTask(param).then(()=>{
    
    
       //刷新列表或者其他操作
});

So far, my needs have been basically realized.

postscript

This article is a reference to the article How to write a message notification component $notify in vue, which is simple and easy to understand, and you can do it!
Further modifications have been made according to their own needs, which are recorded here. It is the first time to package a plug-in, only considering the implementation but not performance and other aspects. There are still many deficiencies. If there is still room for improvement, please feel free to enlighten me.

Guess you like

Origin blog.csdn.net/qq_39352780/article/details/107515792