zoukankan      html  css  js  c++  java
  • 如何优雅的写一个Vue 的弹框

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

    大概有一下几个问题:

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

    2、弹框的函数调用方式

    首先第一点:弹框的层级

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

    第二点:弹框的函数调用

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

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

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

    下面给出弹框的代码: 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%;
         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;
         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("组件不存在");    
        };
    }
    //开始注册组件
    
    var Ruler = {};  //组件的集合
    
    //主动关闭某个组件弹窗  type 组件类型名称, methods  false  取消关闭, true 确认关闭
    Ruler.closeComponents = function (type,methods) {
        if(instance[type] && instance[type]._promise){
            if(methods){
              instance[type]._promise.resolve();
            }else{
              instance[type]._promise.reject();
            }
          instance[type].visible = false;
        }
    }
    
    
    //对弹出组件的初始化处理
    function popupHandle(i,options){
      if(typeof options == "string"){
        options  = {
          msg: options
        }
      }
      return  initComponents(i,options);
    }
    
    
    for(var i in components){
      Ruler[i] = popupHandle.bind(components[i],i);
    }
    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);
          });
    

      

     注意: Vue.extend 初始化的组件,其内部  this.$router 是 undefined ,还有 this.$store 也是,可以直接import 后使用,

    也可以  在组件里面 导入 router 之后,和data 平级,写一个router,,,,这样,组件在传入 Vue.extend的时候,就能够访问到 this.$router 了

    或者在 Vue.extend 以后 new 的时候加入 router ,如:

    instance[type]  = new MessageBoxConstructor({
        el: div,
    	router:router
    });
    

      

    其原理在于: Vue.extend 函数,返回的一个继承了 Vue 的子类。

    也就是说 

    new MessageBoxConstructor  的时候,等同于  new Vue
  • 相关阅读:
    .net core 实现默认图片
    解决ASP.NET Core部署到IIS,更新项目"另一个程序正在使用此文件,进程无法访问"
    c# 按位与,按位或
    找对象,贤妻良母vs事业型
    基于Redis的分布式锁和Redlock算法
    关于free如何知道要释放内存空间的长度问题(X86篇)
    OpenWrt开发教程(五)shell命令操作json api详解(jshn.sh)
    Linux常见错误码声明
    SDN实验---流表项对网络的影响
    delphi 给TComboBox 添加图标
  • 原文地址:https://www.cnblogs.com/muamaker/p/10655440.html
Copyright © 2011-2022 走看看