vue 之 快速模仿Mintui 写一个弹窗插件

1,051 阅读1分钟

1、需求:

用vue 正常写一个弹窗组件想必大家都会,但是如果你想像Mintui 通过以下方式调用, 该如何开发呢?

 let options = {
      content: '展示的内容',
    }
    this.$alert(options).then(() => {
      this.changeStatus("save", true);
    }).catch(e => {
      console.log("取消", e)
    })

2、思路:

2.1 那我们倒着想:要想this.$alert的使用,说明$alert是插件。main.js

main.js 中一定是Vue.use(Alert) 或者Vue.prototype.$alert = Alert;

Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:

// main.js 中
import Alert from "./components/alert/index"
Vue.use(Alert);

2.2 那么如何开发一个Vue.use的插件呢?index.js

import confirmDialog from './confirmDialog.vue'; // 引入弹窗组件样式i
Alert.install = function (Vue) {
    let ConfirmVue = Vue.extend(confirmDialog); // 创建一个构造器
    ConfirmVue.prototype.callBack = defaultCallBack; //添加实例方法
    let container = null;
    Vue.prototype.$alert = (params = {}) => { //添加实例方法
        if (!container) {
            container = new ConfirmVue().$mount() //创建ConfirmVue实例
            document.body.appendChild(container.$el) //挂载到body上
        }
    }

}
export default Alert;

2.3 处理确认后走进.then()函数

如果想要.then 调用, 说明点击确定按钮的时候一定返回了一个promise,那么这里的核心就在于, 你在index.js中的resolve状态不要调用, 要先保存起来, 放在原型方法上, 等到点击确定按钮的时候再去调用this.callBack()

function defaultCallBack(action) {
    if (!action) currentMsg.reject()
    currentMsg.resolve()
}

ConfirmVue.prototype.callBack = defaultCallBack;

return new Promise((resolve, reject) => {
        currentMsg = {
            resolve,
            reject
        }
    })
confirmHandle() { // 点击确认按钮
  this.callBack(true);
  this.isShow = false;
},

总结:

大概思路如下:

步骤1 :

  • 首先新建一个文件夹Alert: 包含 样式组件dialog.vue + index.js(最主要的)
  • 编写一个dialog.vue组件并传入一个options
  • 编写index.js 开发插件(install)
  • main.js中Vue.use(插件)
  • 组件中使用this.$alert插件

index.js详情:

大概思路:

  • 引入dialog.vue组件
  • Alert.install=function(){} 为了之后使用Vue.use()
  • Vue.prototype.alert : 定义原型方法alert
  • ConfirmVue = Vue.extend(dialog) 创建构造器
  • new ConfirmVue() 并appendChild挂载到body中
  • return 一个new promise ,把resolve状态存起来
  • 点击弹窗按钮的时候 调用原型上的回调函数callback

代码:

dialog.vue

<template>
    <div class="confirm-dialog-wrap" @touchmove.prevent v-if="isShow">
      <div class="dialog-box" ref="dialogBox">
        <div class="confirm-header"></div>
        <div class="confirm-content">{{options.content}}</div>
        <div class="button-group">
          <span class="cancel-btn" @click.stop="cancelHandle">{{options.cancelText}}</span>
          <span class="confirm-btn" @click.stop="confirmHandle">{{options.confirmText}}</span>
        </div>
      </div>
    </div>
</template>
<script>
export default {
  data() {
    return {
      options: {
        cancelText: 'Cancel',
        confirmText: 'Confirm',
        content: '这里是内容',
      },
      isShow: false
    }
  },
  methods: {
    show(params) {
      Object.assign(this.options, params) //合并参数
      this.isShow = true;
    },
    cancelHandle() {
      this.callBack(false);
      this.isShow = false;

    },
    confirmHandle() {
      this.callBack(true);
      this.isShow = false;
    }
  },
}
</script>

index.js