闲来无事 撸个vue Dialog组件

309 阅读1分钟

1.实现目标

import Dialog from "@/components/Dialog";

Dialog.alert({
  title: '标题',
  message: '欢迎使用',
}).then(() => {
  console.log('success');
});

Dialog.confirm({
  title: '标题',
  message: '欢迎使用',
}).then(() => {
  console.log('success')
}).catch(() => {
  console.log('cancel');
});

2.组件主体

<template>
  <div class="mask">
    <transition name="scale">
      <div class="dialog" v-if="isShow">
        <h3 class="title">{{title}}</h3>
        <p class="content">{{message}}</p>
        <div class="btn-wrapper">
          <div class="success btn" @click="success">确认</div>
        </div>
      </div>
    </transition>
  </div>
</template>
<script>
export default {
  props: {
    title: {
      type: String,
      default: ""
    },
    message: {
      type: String,
      default: ""
    }
  },
  data() {
    return {
      isShow: false
    };
  }
};
</script>

3.组件配置文件

创建一个新的Vue实例,render函数生成VNode

import Vue from "vue";
import DialogComp from './DialogComp.vue'; // 组件主体

function Dialog(options) {
    const vm = new Vue({
        render(h) {
            // render函数将传入组件对象转换为虚拟dom
            return h(DialogComp, {
            	props: options // 传入组件需要的属性
            });
       }
    }).$mount(); //执行挂载函数,但未指定挂载⽬目标,只执行初始化工作
    // 将⽣生成dom元素追加至body 
    document.body.appendChild(vm.$el);
    const instance = vm.$children[0];
    // 给组件实例例添加销毁⽅方法
    const remove = () => {
        document.body.removeChild(vm.$el);
        vm.$destroy();
    }
    // 返回Promise
    return new Promise((resolve, reject) => {
        instance.isShow = true;
        instance.success = () => {
    	    remove(); // 销毁组件
    	    resolve('ok');
        }
    });
}

Dialog.alert = Dialog;

export default Dialog;

4.实现confirm

Dialog挂载confirm方法,传入 type: 'confirm'

// 返回Promise
return new Promise((resolve, reject) => {
    instance.isShow = true;
    instance.success = () => {
    	remove();
    	resolve('ok');
    }
    // 组件实例挂载取消方法
    instance.cancel = () => {
    	remove();
    	reject('cancel');
    }
});

Dialog.confirm = function (options) {
    return Dialog({
    	type: 'confirm',
    	...options
    });
}
<div class="btn-wrapper">
    <!-- 是否渲染取消按钮 -->
    <div class="cancel btn" @click="cancel" v-if="type === 'confirm'">取消</div>
    <div class="success btn" @click="success">确认</div>
</div>

props: {
    ...
    type: {
      type: String,
      default: "alert"
    }
}

5.运行效果