Vue2实现一个按队列弹消息的弹窗组件

248 阅读1分钟

消息弹框

  1. 支持自定义消息内容
  2. 支持指定消息弹窗的停留时间
<template>
  <div class="xx-message-box"></div>
</template>

<script>
export default {
  props: {
    message: String,
    stayTime: {
      type: Number,
      default: 3000
    }
  },
  mounted() {
    // 停留到指定时间后需要销毁组件
    setTimeout(() => {
      this.$destroy();
    }, this.stayTime);
  }
};
</script>

<style>
.xx-message-box {
  position: fixed;
  left: 0;
  right: 0;
  margin: auto;
  width: fit-content;
  z-index: 9999999;
  padding: 5px;
  background: #e8f3ff;
  color: var(--juejin-brand-1-normal);
  border-radius: 5px;
  white-space: pre-wrap;
  line-height: 1.8;
}
</style>

以全局函数的方式使用

import Vue from 'vue';

const MessageConstructor = Vue.extend(Message);

// 外部调用 message('这是一条消息!')
// 或者 message({ message: '这是另一条消息!' })
export function message(options) {
  if (typeof options === 'string') {
    options = { message: options };
  }
  const instance = new MessageConstructor({ propsData: options });
  instance.$on('hook:mounted', function() {
    document.body.appendChild(this.$el);
  });
  instance.$on('hook:destroyed', function() {
    this.$el.remove();
  });
  instance.$mount();  
}

需要在弹窗关闭后做一些事

// 返回一个promise
export function message(options) {
  return new Promise(resolve => {
    if (typeof options === 'string') {
      options = { message: options };
    } 
    const instance = new MessageConstructor({ propsData: options });
    instance.$on('hook:mounted', function() {
      document.body.appendChild(this.$el);
    });
    instance.$on('hook:destroyed', function() {
      this.$el.remove();
      resolve();
    });
    instance.$mount(); 
  }); 
}

使用队列处理同时有多条消息

const messageQueue = [];
// 当前正在展示的消息
let currentMessage = null;

function handleNextMessage() {
  // 没有消息时,置空
  currentMessage = messageQueue.shift();
  currentMessage?.$mount();
}

export function message(options) {
  return new Promise(resolve => {
    if (typeof options === 'string') {
      options = { message: options };
    } 
    const instance = new MessageConstructor({ propsData: options });
    instance.$on('hook:mounted', function() {
      document.body.appendChild(this.$el);
    });
    instance.$on('hook:destroyed', function() {
      this.$el.remove();
      // 展示下一条消息
      handleNextMessage();
      resolve();
    });
    // 有正在展示的消息时,将新创建的消息实例加入到队列中
    if (currentMessage) {
      messageQueue.push(instance);
    } else {
      currentMessage = instance;
      instance.$mount();
    }
  }); 
}