如何优雅的写一个Vue 的弹框

写Vue或者是react 都会遇见弹框的问题。也尝试了多种办法来写弹框,一直都不太满意,今天特地看了一下 Element UI 的源码,模仿着写了一个简易版。

大概有一下几个问题:

1、弹框的层级问题,如果在嵌套的组件里面使用了弹框,可能会出现弹框的层级不够高

2、弹框的函数调用方式

首先第一点:弹框的层级

如果将弹框放置在最外层,body下面。就不会有层级问题。

第二点:弹框的函数调用

首先我们可以思考,将组件的实例拿到,然而初学的时候好像只有 通过  refs 能拿到组件的对象,然后调用显示隐藏

其实我们可以通过 VUE.extend  这个函数,对组件进行初始化,然后可以拿到 组件对象

对于 Vue.extend 不太清楚的,建议自己去百度学习一下。

扫描二维码关注公众号,回复: 5776392 查看本文章

下面给出弹框的代码: alert.vue 文件下面

<template>
    <div class="_alert" v-show="visible">
        <div class="wind-alert">
	        <div class="wind-alert-bg"></div>
	        <div class="wind-alert-dialog animate-scale">
	          <div class="wind-alert-title">{{title}}</div>
	          <div class="wind-alert-content">{{content}}</div>
	          <div class="wind-alert-btn" @click="close">{{btn}}</div>
	        </div>
	    </div>
    </div>
</template>
<script>
export default {
    name:"rule_alert",
     data() {
	    return {
            title: '提示',
            content:  '',
            btn:  '确定',
            visible:false
        }
    },
    methods: {
        close() {
            this.visible = false;
           this._promise &&  this._promise.resolve()
        }
    },
    watch: {
        '$route' () {
            this.close();
        }
    }
}
</script>
<style>
.wind-alert-dialog {
    top: 30%;
    width: 80%;
    left: 50%;
    opacity: 1;
    position: fixed;
    margin-left: -40%;
    font-size: 14px;
    text-align: center;
    font-family: 'Microsoft Yahei';
    background: #FFFFFF;
    border-radius: 8px;
    z-index: 999999999;
    box-sizing: content-box;
}

.wind-alert-bg {
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    opacity: 0.3;
    display: block;
    position: fixed;
    z-index: 999999998;
    background-color: #000000;
}

.wind-alert-title {
    font-size: 17px;
    padding: 20px 5px 0;
}

.wind-alert-content {
    padding: 5px 15px 20px 15px;
    border-bottom: 1px solid #ededed;
}

.wind-alert-btn {
    color: #0582cd;
    font-size: 15px;
    line-height: 40px;
    font-weight: bold;
}

.animate-scale {
    animation-name: scale;
    animation-duration: 0.375s;
}

@keyframes scale {
    0%{
        transform: scale(0);
    }
    100% {
        transform: scale(1);
    }
}
</style>

  

接下来,就是将这个组件,进行初始化,并且注入一些自己的方法和属性

这个地方的注入,是一个公共的方法,后面可以引入其他类型的弹框,比如 comfirm 类型的

新建  plugin.js

import Alert from "@/components/alert";

import Vue from "vue";

//原始组件
var components = {
    Alert:Alert
}

var instance = {}; //缓存组件的实例
var Ruler = {};  //组件的集合
var body  =  document.body || document.documentElement;
var root = document.createElement("div");
body.appendChild(root);

//初始化构造vue组件,并且注入自己的代码
const initComponents = function(type,options){
    options  =  options || {};
    type = type || '';
    if(components[type]){   
        if(!instance[type]){
            //避免重复的初始化
            var div = document.createElement('div');
            root.appendChild(div);
            const MessageBoxConstructor = Vue.extend(components[type]);
              
            instance[type]  = new MessageBoxConstructor({
                el: div
            });
        }
        var ins = instance[type];
        //复制属性
        for(var i in options){
            ins[i] = options[i];
        }
        Vue.nextTick(()=>{
            ins.visible = true;
        })
        return new Promise(function(resolve,reject){
            //注入当前的 promise
            ins._promise = {
                resolve,
                reject
            };
        }).finally(()=>{
            //ins.visible = false;
            //可以在这里监听,不管结果如何,最后执行一段代码
        });
    }else{
        return Promise.reject("组件不存在");    
    };
}



Ruler.Alert = function(options){
    options = options || {
        title: '提示',
        content:  '',
        btn:  '确定',
   }; 
   if(typeof options == "string"){
    options  = {
        title: '提示',
        content: options,
        btn:  '确定',
    }
   }
   return  initComponents("Alert",options);
} 


export default{
    install(Vue){
       Vue.prototype.$Ruler = Ruler;
    }
}

  

接下来就是在 main.js 里面引入了:

import plugin from "@/plugin/plugin";
Vue.use(plugin);

  

然后在任意的地方使用

this.$Ruler.Alert("这是一个提示").then((ret)=>{
          console.log("then",ret);
      }).catch((e)=>{
          console.log("catch",e);
      });

  

猜你喜欢

转载自www.cnblogs.com/muamaker/p/10655440.html