如何封装一个全局直接调用的toast

1,473 阅读1分钟

在我们日常工作中,经常会使用一些UI框架,比如:vant、elementui、antdesign等,但是在使用时,一般需要手动import一下,那有没有可能,我不通过import直接在全局调用呢,就像一个全局方法一样。

vue就为我们提供了这样的一个Api -- Vue.extend(options)。创建一个“子类”。参数是一个包含组件选项的对象。我们可以将组建封装成函数的形式,直接通过调用全局方法的形式调用它。注意:data选项是特例,在Vue.extend()中它必须是函数。

Vue.extend以组件为入参,那么首先我们要先写一个组件,这个组件要包含一些基本的默认值,要有展示toast与隐藏toast的控制,可以设置一个状态值,通过监控这个值来展示与隐藏。组件代码如下:

<template>
  <div v-show="visible" class="toast">
    {{ message }}
  </div>
</template>

<script>
export default {
  name: 'toast',
  data() {
    return {
      message: '', // 默认的提示信息
      visible: false, // 是否可见
      duration: 3000, //默认三秒
      timer: null, // 计时的,用作判断
      closed: false, // 判断是否已经关闭
    };
  },
  watch: {
    closed(newVal) {  // 监听closed的值变化,用来控制组件的展示隐藏,及销毁
      if (newVal) {
        this.visible = false;
        this.destroyElement();
      }
    },
  },
  mounted() {
    this.startTimer(); // 组件挂载后,先做展示
  },
  methods: {
    startTimer() {
      this.visible = true;
      this.timer = setTimeout(() => {
        if (!this.closed) {
          this.closed = true;
          clearTimeout(this.timer);
        }
      }, this.duration);
    },
    destroyElement() { // 销毁组件
      this.$destroy();
      this.$el.parentNode.removeChild(this.$el); // 将组建从dom节点移除
    },
  },
};
</script>

上面是一个toast组件所需要的模板与js处理,那么如果做到全局直接调用呢。Vue.extend可以生成一个组件的构造函数,可以通过 new 的方式,创建一个组件实例。再通过实例的挂载及层级的控制,来做处理,代码如下:

import Vue from 'vue';
import Toast from './toast.vue';

let ToastConstructor = Vue.extend(Toast);
let instance // 实例对象
let seed = 0; // 确定有多少这样的实例,控制层级

const ToastDialog = (options ={})=>{
    if (typeof options === 'string') { // 支持只传入文案提示
        options = {
            message: options
        }
    }

    let id = `toast_${seed++}`
    instance = new ToastConstructor({
        data:options // 可以与组件内部的data进行合并,如果key相同可以将原来的值替换掉
    })
    console.log(instance,'instance is ----')
    instance.id = id;
     /* 因为还没有具体的dom节点可以挂载此处$mount没有提供参数,
     模板将被渲染为文档之外的的元素,必须使用原生DOM API把它插入文档中 */
    instance.vm = instance.$mount();
    document.body.appendChild(instance.vm.$el); // 将实例挂载到dom上
    instance.vm.visible = true;
    instance.dom = instance.vm.$el;
    instance.dom.style.zIndex = 999 + seed;
    console.log(instance,'instance is ----');
    return instance.vm;
}
export default ToastDialog;

做完以上这些,还没有完事,需要将该实例方法,添加到vue的全局方法中:

Vue.prototype.$toast = Toast;

然后就哪里需要哪里调用就可以了:

this.$toast('记得吃饭···')