仿ElementUI写一个弹窗插件

189 阅读1分钟

愿景

  • 实现一个简单的弹窗组件,主要思路是将组件配置对象转换为组件构造函数,并挂在到body上 代码实现,在使用this.$notice()的时候生成组件构造函数,并调用组件内部的show()方法
    // create.js
    import Vue from "vue"
    // 将组件配置对象转换为组件构造函数
    export default function create(Component, props) {
      // 1. 转换为组件构造函数
      // 1.1 Vue.extend(Comp)
      const Ctor = Vue.extend(Component)
      const comp = new Ctor({
        propsData: props
      })
      // 2.手动挂载到body上
      comp.$mount() // 只挂载 vdom => dom
      // 挂载之后$el就填充了
      // 手动追加至body
      document.body.appendChild(comp.$el)
      // 释放资源
      comp.remove = function() {
        document.body.removeChild(comp.$el)
        comp.$destroy()
      }
      return comp
      // 1.2 new Vue({render: h => h(Comp)}) // 实现2
    }
    // notice.js 暴露install供Vue.use()调用
    import Notice from "../dialog/notice.vue";
    import create from "./create.js";
    class NoticeCtor {
      constructor() {}
    }
    NoticeCtor.install = function (Vue) {
      Vue.prototype.$notice = function (props) {
        const notice = create(Notice, props);
        notice.show()
        return notice
      }
    }
    export default NoticeCtor
    // notice.vue
    <template>
      <div class="box" v-if="isShow">
        <h3>{{ title }}</h3>
        <p class="box-content">{{ message }}</p>
      </div>
    </template>
    <script>
    export default {
      props: {
        title: {
          type: String,
          default: "",
        },
        message: {
          type: String,
          default: "",
        },
        duration: {
          type: Number,
          default: 1000,
        },
      },
      data() {
        return {
          isShow: false,
        };
      },
      methods: {
        show() {
          this.isShow = true;
          setTimeout(this.hide, this.duration);
        },
        hide() {
          this.isShow = false;
          this.remove();
        },
      },
    };
    </script>
    <style>
    .box {
      position: absolute;
      width: 300px;
      height: 140px;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      margin: auto;
      text-align: center;
      pointer-events: none;
      background-color: #fff;
      border: grey 3px solid;
      box-sizing: border-box;
    }
    .box-content {
      width: 200px;
      margin: 10px auto;
      font-size: 14px;
      padding: 8px 16px;
      background: #fff;
      border-radius: 3px;
      margin-bottom: 8px;
    }
    </style>
    // main.js
    import NoticeCtor from './utils/notice'
    Vue.use(NoticeCtor)

使用

    this.$notice({
      title: "社会你海哥喊你来搬砖",
      message: "demo小测试",
      duration: 1000,
    })

效果

image.png