专栏首页明年我18关于el-dialog,我更推荐的用法

关于el-dialog,我更推荐的用法

最近的项目里用上了vue和element-ui。vue这种轻量级渐进式框架的舒适自不必说,但一直困扰着我的,是如何方便又优雅的弹出模态dialog...

对于我这种在jquery出现之前就用document.getElementById敲代码的老顽固来说,我始终不能完全接受把dialog在编码期就写入模板的方式,下面是尤大在知乎某个相关问题的回答节选(全文请看https://www.zhihu.com/question/35820643):

为什么一定要异步插入? 其实以前也有一些用户跟我纠结过这个问题,他们觉得一定要在需要的时候创建这个组件才是符合他们思维的做法。在我看来,这是没有理解『状态驱动的界面』的一种表现。 传统的命令式 (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下才能避免这样那样的问题,就比如本文要说的element-ui的el-dialog问题:如果你在一个el-dialog里,嵌套了另外一个el-dialog,那么弹窗的遮罩层会相互影响,导致用户无法使用(新发布的element-ui 2.0已经解决了嵌套弹窗的问题,文档在这里http://element.eleme.io/#/zh-CN/component/dialog)。

这就要求我们把系统中所有可能出现的dialog,都预先放在vue的根组件中,但显然这是不合理的,根组件无法预知业务模块中将会出现的dialog。dialog应该和alert、messagebox、toast一样,提供方法级别的调用,但不知为何element-ui为后者们提供了全局方法,但对dialog却没有。

本文的目的,就是为了分享一个为dialog提供全局方法的做法。这是我在csdn上看到的一篇文章,确实解决了我的问题,原文在这里:http://blog.csdn.net/zmy_coder/article/details/78042485

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

//dialog.js
function makeDialog(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" \
            :size="size" \
            :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,
                size: option.size || 'small',
                show: true,
                dialogData: option.data,
            };
        },
        template: tpl,
        computed: {
            customClass(){
                return `el-dialog--width-${option.size || '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 {
    open(options){
        return makeDialog(options)
    }
}

在创建的这个Vue实例里,用到了el-dialog组件,并且具体的内容由外部调用者以component的形式传入,如果该component需要初始数据,需要为该component定义一个value属性,并且在调用open方法时,用options.data传入,并且可以设置在对话框beforeClose、close、confirm时的回调

用法示例:

对话框内容:

<!--SimpleDialogTest.vue-->
<template>
    <div class="tutorial">
        请输入您的姓名 <input class="form-control" v-model="name">

        <button type="button" class="btn btn-primary" @click="submit">确定</button>
        <button type="button" class="btn btn-default" @click="cancel">取消</button>
    </div>
</template>
<style lang="scss" rel="stylesheet/scss" scoped>

</style>
<script type="text/ecmascript-6">
    import dialog from '../../assets/js/dialog'
    export default{
        props: {
            value: Object,
        },
        data(){
            return {
                name : this.value.name
            }
        },

        methods: {
            submit(){
                console.log('your name is ' + this.name)
                //do something if you like
                //...

                //关闭对话框
                this.$emit('close');

                //关闭对话框, 并回调调用者的option.confirm方法
//                this.$emit('confirm', {
//                        ...
//                });
            },
            cancel(){
                this.$emit('close')
            }
        },

    }
</script>

调用方:

<!---调用方-->
<template>
    <button @click="openDialog">弹出对话框</button>
</template>
<script type="text/ecmascript-6">
    import dialog from '../assets/js/dialog'
    import SimpleDialogTest from 'SimpleDialogTest.vue'
    export default{
        data(){
            return{
            }
        },
        methods:{
            openDialog(){
                dialog.open({
                    title: '标题标题',
                    size:'small', //可选项tiny/small/large/full, 对应el-dialog的size属性
                    component: SimpleDialogTest,
                    data: {
                        name: 'your name',
                    },
//                    beforeClose: (done) => {
//                        //点右上角关闭按钮后触发
//                        console.log('dialog is closing');
//                        done()
//                    },
                    close: () => {
                        //关闭后触发
                        console.log('dialog is closed')
                    },
                    confirm: (result) => {
                        //显式$emit('confirm')时触发
                        console.log('dialog is confirmed, and dialog result is ', result)
                    }
                })
            }
        }
    }
</script>

关于option的size

el-dialog中size的四个选项tiny/small/large/full在实际应用中是不够的,有时候我们希望能为dialog能自适应内容组件的宽度,也就是说由内容组件来决定宽度,应该怎么做呢?

首先定义一个全局的css:

.el-dialog.el-dialog--width-auto{
  width:auto !important;
}

然后在调用dialog.open()的时候,不要指定size属性就行了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 开发一个Word的代码高亮插件

    在用Word写技术文档的时候,免不了要在文档中插入一些源代码。为了使插入进来的源代码更可读,就需要使这些代码的关键字高亮显示。所以在写这些文档的时候,我经常需要...

    明年我18
  • 实现类似“添加扩展程序…”的设计时支持

    Ajax Control Toolkit这个控件库内包含一些扩展控件,利用这些扩展控件,可以非常方便的为普通的控件添加Ajax效果,例如,利用AutoComp...

    明年我18
  • ThreadLocal原理分析与代码验证

    ThreadLocal提供了线程安全的数据存储和访问方式,利用不带key的get和set方法,居然能做到线程之间隔离,非常神奇。

    明年我18
  • 基于网页接口做自动化测试(基于HttpRunner+Fiddler)

    1.安装Fiddler ,可以参考 http://together-learn.com/post/263

    海涛
  • 排序算法-基数排序

    排序算法-基数排序 <?php /** * php算法实战. * * 排序算法-基数排序 * * 分为两种LSD,MSD * * LSD: * ...

    琯琯
  • HashMap和HashTable的区别和联系

    线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问某个数据时,进行加锁保护,其他线程不能进行访问,直到该线程任务结束,其他线程才可使用。不会出现数据不一...

    IT云清
  • IDA动态调试-没啥卵用的静态加固

    前几天学习了so加固相关的知识so加固-加密特定section中的内容、ELF中可以被修改又不影响执行的区域,于是自己动手写了一个crackme,自我感觉么么哒...

    用户2930595
  • greenplum资源队列

    Description: create a new resource queue for workload management

    用户6805534
  • Leetcode 207 Course Schedule

    There are a total of n courses you have to take, labeled from 0 to n - 1. Som...

    triplebee
  • 机器学习5:集成学习--Bagging与随机森林

    对于训练集数据,通过训练若干个个体学习器,通过一定的结合策略,就可以最终形成一个强学习器,以达到博采众长的目的。

    用户5473628

扫码关注云+社区

领取腾讯云代金券