vue实现全局自定义message提示消息弹窗

4,548 阅读3分钟

一、前言

element ui的message弹窗很好用,但需求却说不够酷炫,说是要改改样式。

说干就干,这就来实现一个全局消息弹窗。

今天的文章基本上代码占比大一点,可以跟着代码里的注释,来一步步理解。

二、过程

整体由两部分构成,作为弹窗模板的ai-messageMain.vue文件,和作为弹窗构造器的ai-messageExtend.js文件。

1、弹窗模板

ai-messageMain.vue文件

css样式可以自己自定义修改。

<template>
<!-- ai的message弹窗内容 -->
  <transition name="taataa">
    <div :class="['plugins-message-box',type]" v-if="visible">
      <div :class="['message-icon','iconfont',iconClass]">
        <!-- <span class="message-container">{{message}}</span> -->
        <div class="spantext">{{message}}</div>
      </div>
    </div>
  </transition>
</template>

<script>
const typeClass = {
  success: "icon-success",
  error: "icon-error",
  warning: "icon-warn",
  info: "icon-info"
};
export default {
  name: "messageMain",
  data() {
    return {
      visible: false, // 控制DOM显示隐藏
      type: "success", // 默认type值为default
      icon: "", // 默认使用icon为空,则使用type值对应的icon
      message: "", // 默认的message为空,由外部传入
      duration: 2000, // 默认显示时间为2000ms
    };
  },
  computed: {
    // 如果外部传入icon则使用外部的icon,如果没有。则使用type值对应的icon
    iconClass() {
      if (this.icon) {
        return this.icon;
      } else {
        return typeClass[this.type];
      }
    },
  },  
};
</script>
<style lang="scss" scoped>
.plugins-message-box {
  position: fixed;
  z-index: 989;
  left: 50%;
  top: 10%;
  transform: translate(-50%, 0%);
  -webkit-animation: comein 1s  linear;
  animation: comein 1s  linear;
  pointer-events: none;
  .icon-error {
    width: 432px;
    height: auto;
    padding: 20px 60px 20px 100px;
    background: rgba(63,12,12,0.8);
    border-radius: 6px;
    color: #FFE3E3;
    text-align: left;
    font-size: 16px;
    font-family: 'pfFont';
    position: relative;
    .spantext {
      display: inline-block;
      width: 100%;
      // 换行设置
      white-space:pre-wrap;
      word-wrap: break-word;
      height: auto;
      line-height: 20px;
      @include ellipsis(5);
    }
  }
  .icon-success {
    width: 432px;
    height: auto;
    padding: 20px 60px 20px 100px;
    background: rgba(17,52,45,0.8);
    border-radius: 6px;
    color: #D5FFE3;
    text-align: left;
    font-size: 16px;
    font-family: 'pfFont';
    position: relative;
    .spantext {
      display: inline-block;
      width: 100%;
      // 换行设置
      white-space:pre-wrap;
      word-wrap: break-word;
      height: auto;
      line-height: 20px;
      @include ellipsis(5);
    }
  }
  .icon-warn {
    width: 432px;
    height: auto;
    padding: 20px 60px 20px 100px;
    background: rgba(61,55,14,0.8);
    border-radius: 6px;
    color: #FDE8C8;
    text-align: left;
    font-size: 16px;
    font-family: 'pfFont';
    position: relative;
    .spantext {
      display: inline-block;
      width: 100%;
      // 换行设置
      white-space:pre-wrap;
      word-wrap: break-word;
      height: auto;
      line-height: 20px;
      @include ellipsis(5);
    }
  }
  .icon-info {
    width: 432px;
    height: auto;
    padding: 20px 60px 20px 100px;
    background: rgba(33,80,109,0.8);
    border-radius: 6px;
    color: #C8E3FD;
    text-align: left;
    font-size: 16px;
    font-family: 'pfFont';
    position: relative;
    .spantext {
      display: inline-block;
      width: 100%;
      // 换行设置
      white-space:pre-wrap;
      word-wrap: break-word;
      height: auto;
      line-height: 20px;
      @include ellipsis(5);
    }
  }
}
@keyframes comein {
  0% {
    top: -20%;
    opacity: 0.3;
  }
  100% {
    top: 10%;
    opacity: 1;
  }
}
</style>

2、弹窗构造器

ai-messageExtend.js

import Vue from 'vue'; // 引入Vue
import MessageMain from './ai-messageMain'; // 引入上边定义好的message模板
const MessageBox = Vue.extend(MessageMain); // 使用Vue.extend来创建一个构造器
let instance; // instance 变量用来保存实例
let timer = null; // timer 变量用来保存定时器
// 定义一个function,参数为options,默认为一个对象
const Message = function (options = {}) {
  console.log(options)
    // 如果当前处在服务器端,则直接返回
    if (Vue.prototype.$isServer) return;
    // 如果当前定时器已开启,说明页面上已经有一个message-box了,则不能再继续创建新的message-box
    if (timer) return;
    // 对options做处理,如果直接传入string,则使其保存在options的message属性上
    if (typeof options === 'string') {
        options = {
            message: options
        }
    }
    // 初始化实例,并将options作为新的data传入,Vue会将options合并到原有的data上,覆盖原有的默认值,但是,在options中没有设置的是不会被改变的
    instance = new MessageBox({
        data: options
    });
    // 调用$mount方法,将当前实例渲染为真实DOM,生成$el,如果不执行这一步,将拿不到 $el 的值,但是不指定DOM节点接管当前实例
    instance.vm = instance.$mount();
    // 使用原生js的API将当前实例的真实DOM追加到body中
    document.body.appendChild(instance.vm.$el);
    // 实例上的vm就是我们的Vue组件,所以我们可以通过vm访问到当前实例中的所有属性
    // 将visible设置为true,即显示当前message-box
    instance.vm.visible = true;
    // console.log(instance, document.body)
    // 开启定时器
    timer = setTimeout(() => {
        instance.vm.visible = false;
        // 清除定时器
        timer = null;
    }, instance.vm.duration);
    // 定时器的时间使用vm中定义的时间
    return instance.vm;
};
// 最终抛出一个对象,对象上我们可以使用 install 来扩展Vue的插件
// 当我们的对象上有install方法的时候,它接收第一个参数为Vue,
// 我这里为了方便使用,还在当前抛出的对象上定义了一个message方法,为了方便在axios的拦截器中使用;
export default {
    Message: Message,
    install(Vue) {
        Vue.prototype.$message = Message;
        Vue.message = Message;
    }
};

3、全局挂载

在main.js里挂载

import Message from './components/ai-monitor-center/ai-messageExtend.js'
Vue.prototype.$MessageAi = MessageAi

4、在能访问到this的文件里调用

this.$MessageAi.Message({
    type: 'success',
    message: '修改成功'
  })

5、访问不到this实例的,需要额外导入构造器

import MessageAi from './components/ai-monitor-center/ai-messageExtend.js'

然后使用MessageAi调用生成。

6、最终效果

可以看到,默认的弹窗已经换成我们的自定义样式了。 image.png

ps: 我是地霊殿__三無,希望能帮到你。

Snipaste_2022-07-19_15-30-26.jpg