近期我司正在开发一个新的项目,期间遇到过很多问题,但是通过努力都得道了解决,现在项目还在一步一步的进行中,今天就给大家说一下我在使用vue+element项目开发中遇到的dialog问题:

1.弹框不支持嵌套

在element 2.0版本之前dialog是不支持嵌套的,后面element升级到2.0之后是支持嵌套的,只需要给dialog添加 append-to-body 属性即可。但是虽然之前弹窗项目嵌套,但是element中的dialog并不支持,多级弹窗之前的连续回调,即子弹窗无法控制父弹窗的关闭,或者其他操作。

2.多个弹框之间遮罩层会相互影响

当项目中一个页面中使用多级弹窗的时候,再不考虑回调函数的同时,还有一个很大的问题,就是多个弹窗之间的遮罩层会相互影响,你会发想弹窗越来越多,遮罩会变得越来越黑 =_=||

解决方案 ==> setTimeout

针对上面阐述的两个问题,我做了一些简单的操作,首先是通过在父组件的监听函数里面加了一个setTimeout,并且这个方式达到了我们预期的效果,能够让子组件控制父组件甚至父父组件的关闭。代码如下:

子组件代码:

/*
        * 监听子组件通讯的方法
        * 作用:根据不同的参数关闭对应的模态
        * @param targer string example:"add""edit"
        * */
        cancel(targer){
          let that = this;
          this[targer+'Modal'] = false;
          setTimeout(function(){
            that.$emit('cancel','edit');
          },10)
        }复制代码

父组件代码:

/*
       * 监听子组件通讯的方法
       * 作用:根据不同的参数关闭对应的模态
       * @param targer string example:"add""edit"
       * */
      cancel(targer){
        that[targer+'Modal'] = false;
      },复制代码

这种方式通过延时器的方式,可以说是取了一下巧,但是当你的页面出现很多的弹窗的时候,你需要分别定义不同的名称,然后对不同的弹窗做不同的处理,非常麻烦。

解决方案二 ==> 通过实例vue对象

尤大曾在知乎某个相关的问题说过这样的话:
为什么一定要异步插入?
其实以前也有一些用户跟我纠结过这个问题,他们觉得一定要在需要的时候创建这个组件才是符合他们思维的做法。在我看来,这是没有理解『状态驱动的界面』的一种表现。
传统的命令式 (Imperative) 的思维写出来的代码:

$('.open-modal').on('click', function () {
 var modal = new Modal()
 modal.$appendTo('body')
 modal.open()
})复制代码

// 在 modal 内部还要处理关闭、销毁自身的逻辑
状态驱动的思维写出来的代码:

this.showModal = true

// 关掉
this.showModal = false复制代码

不可否认,尤大所说的状态驱动确实是vue的精髓,但是在实际应用中,dialog往往需要直接在body下才能避免这样那样的问题,后来在csdn上看到的一篇文章,确实解决了我的问题。原文链接

原理就是在方法被调用时,在body里create一个div,并且创建一个Vue实例,指定el属性为这个div。

下面是我定义的dialog.js

import Vue from 'vue'

function Dialog (option)  {
    var dom = document.createElement('div');
    document.getElementsByTagName('body')[0].appendChild(dom);
    let tpl = '\
        <el-dialog \
            :close-on-click-modal="false" \
            :custom-class="customClass" \
            :title="title" \
            :visible.sync="show" \
            :width="width" \
            :before-close="handleClose" \
            @close="close">\
                <dialogContent  @close="closeDialog" @confirm="confirmDialog" v-model="dialogData"></dialogContent>\
        </el-dialog>';
    var vue = new Vue({
        el: dom,
        data: function () {
            return {
                title: option.title,
                width: option.width || '1000px',
                show: true,
                dialogData: option.data,
            };
        },
        template: tpl,
        computed: {
            customClass(){
                return `el-dialog--width-${option.width || 'auto'}`;
            }
        },
        methods: {
            handleClose(done){
                if (option.beforeClose) {
                    option.beforeClose(done);
                } else {
                    done();
                }
            },
            close() {
                if (option.close) {
                    option.close();
                }
            },

            closeDialog(){
                this.show = false
            },
            confirmDialog(result){
                this.show = false
                option.confirm && option.confirm(result)
            }
        },
        components: {
            dialogContent: option.component,
        },
    });
    return vue;
}
export default Dialog复制代码

项目地址

我将代码整体整理了一个demo,demo中包含了,单一弹窗,多级弹窗(多级弹窗分为两个,一个是关闭当前,一个是关闭所有),希望能对大家有所帮助。

项目地址

喜欢的可以关注我,有时间就会更新一些自己工作或生活中遇到的一些小问题以及解决方案

Logo

前往低代码交流专区

更多推荐