通过 Vue.extend() 创建可指令调用的 messageBox 弹窗组件源码

前言

本文是《通过 Vue.extend() 创建可指令调用的组件——MessageBox 弹框》的扩展。关于Vue.extend()的用法以及 messageBox 弹窗实现的思路,可查看前文

项目目录

...
├── src
...
│?? ├── plugins
│?? │?? ├── messageBox 
│?? │?? │?? ├── messageBox.vue
│?? │?? │?? └── main.js
...
│?? ├── App.vue
│?? └── main.js
...

messageBox 弹窗组件代码—— messageBox.vue

<template>
  <transition name="extends">
    <div v-show="visible" id="messageBox" class="messageBox" @click="cloceModal">
      <div class="contain">
        <header>
          <i class="close el-icon-close" v-if="showClose" @click="close"></i>
        </header>
        <main>
          <div>
            <img v-if="type === 'success'" src="@/plugins/modules/messageBox/assets/success.svg" />
            <img v-if="type === 'warning'" src="@/plugins/modules/messageBox/assets/warning.svg" />
            <img v-if="type === 'error'" src="@/plugins/modules/messageBox/assets/error.svg" />
            <img v-if="type === 'info'" src="@/plugins/modules/messageBox/assets/info.svg" />
            <img v-if="type === 'question'" src="@/plugins/modules/messageBox/assets/question.svg" />
          </div>
          <div class="content">
            <h3 v-if="title">{{ title }}</h3>
            <p v-if="dangerouslyUseHTMLString" v-html="message"></p>
            <p v-else :class="{ large: !title }">{{ message }}</p>
          </div>
        </main>
        <footer>
          <el-button v-if="showCancelButton === true" @click="close">{{ cancelButtonText }}</el-button>
          <el-button type="primary" @click="confirm">{{ confirmButtonText }}</el-button>
        </footer>
      </div>
    </div>
  </transition>
</template>
<script>
export default {
  name: 'message-box',
  data() {
    return {
      visible: false,
      message: '',
      title: '',
      lockScroll: true,
      showCancelButton: true,
      dangerouslyUseHTMLString: false,
      showClose: false,
      closeOnClickModal: false,
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      type: 'success', // success、warning、error、info、question
      callback: null
    };
  },
  created() {
    if (this.lockScroll) {
      // 是否在 MessageBox 出现时将 body 滚动锁定
      document.body.classList.add('messageBox-srcoll-hideen');
    }
    this.$nextTick(() => {
      this.visible = true;
    });
  },
  methods: {
    close() {
      this.visible = false;
      this.callback && this.callback(false);
      this.remove();
    },
    cloceModal() {
      if (this.closeOnClickModal) {
        this.close();
      }
    },
    confirm() {
      this.visible = false;
      this.callback && this.callback(true);
      this.remove();
    },

    // 组件移除事件
    remove() {
      // 等过渡效果结束后,再移除组件
      setTimeout(() => {
        this.$destroy(this);
        document.body.classList.remove('messageBox-srcoll-hideen'); // 移除蒙版
        this.$el.remove(); // 移除组件 DOM
      }, 500);
    }
  }
};
</script>
<style lang="scss">
.messageBox-srcoll-hideen {
  overflow: hidden;
}
.messageBox {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 3000;
  width: 100%;
  height: 100%;
  background-color: rgba($color: #000000, $alpha: 0.2);
  .contain {
    position: absolute;
    top: 45%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 500px;
    height: 240px;
    border-radius: 4px;
    background-color: #ffffff;
    box-shadow: 0 0 16px 0 rgba($color: #000000, $alpha: 0.1);
    header {
      width: 100%;
      height: 36px;
      text-align: right;
      padding: 5px;
      .close {
        display: inline-flex;
        justify-content: center;
        align-items: center;
        width: 36px;
        height: 36px;
        font-weight: bold;
        cursor: pointer;
        &:hover,
        &:focus {
          background: rgba($color: #1367da, $alpha: 0.08);
          border-radius: 4px;
          color: #1367da;
        }
      }
    }
    main {
      display: flex;
      width: 100%;
      max-height: 127px;
      overflow-y: hidden;
      padding: 30px 40px;
      & > div:first-child {
        width: 40px;
        height: 40px;
      }
      .content {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        width: 350px;
        min-height: 40px;
        padding-left: 16px;
        & * {
          width: 100%;
        }
        h3 {
          margin-bottom: 4px;
          font-size: 18px;
          font-weight: bold;
          color: #333333;
          line-height: 22px;
        }
        p {
          text-align: left;
          font-size: 14px;
          color: #999999;
        }
        .large {
          font-size: 18px;
          color: #333333;
        }
      }
    }
    footer {
      position: absolute;
      bottom: 0;
      width: 100%;
      height: 67px;
      padding: 13px 16px;
      text-align: right;
    }
  }
}
</style>

messageBox 弹窗组件代码——main.js

import Vue from 'vue';
import messageBoxVue from '@/plugins/modules/messageBox/messageBox.vue';

const MessageBox = Vue.extend(messageBoxVue); // 直接将Vue组件作为Vue.extend的参数

const messageBox = (message, title, config = {}) => {
  return new Promise((resolve, reject) => {
    const callback = ret => {
      if (ret === true) {
        resolve();
      } else if (ret === false) {
        reject();
      }
    };
    const messageBox = document.querySelector('#messageBox'); // 查询页面现有的 messageBox
    if (messageBox) {
      // 如果已经存在 messageBox,则停止新的 messageBox 创建
      return false;
    }

    const instance = new MessageBox({
      data: {
        message: message,
        title: title,
        lockScroll: config?.lockScroll === false ? false : true, // 是否在 MessageBox 出现时将 body 滚动锁定
        dangerouslyUseHTMLString: config?.dangerouslyUseHTMLString || false, // 是否将 message 属性作为 HTML 片段处理, 默认为 false
        showCancelButton: config?.showCancelButton === false ? false : true, // 取消按钮显示隐藏,默认 true
        showClose: config?.showClose === false ? false : true, // 默认 true
        confirmButtonText: config?.confirmButtonText || '确认', // 未配置文本,默认‘确认’
        cancelButtonText: config?.cancelButtonText || '取消', // 未配置文本,默认‘取消’
        type: config?.type || 'success',  // 弹窗类别
        callback: callback
      }
    });
    instance.$mount(); // 挂载但是并未插入dom,是一个完整的Vue实例
    document.body.appendChild(instance.$el); // 将dom插入body
  });
};

export default {
  install: Vue => {
    Vue.prototype.$messageBox = messageBox; // 将组件暴露出去,并挂载在Vue的prototype上
  }
};

在 vue 入口文件 main.js 中引用

import Vue from 'vue';
import messageBox from '@/plugins/messageBox/main.js';

Vue.use(messageBox);
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值