模态框vue组件

 

vue模态框

modal.vue

<template>
    <div>
        <div class="dialog-mask" v-show="visible" v-if="maskhide"></div>
        <div class="dialog" @click.self="maskClose" v-show="visible">
            <div class="dialog-main" 
            :style="dialogStyle"
            :class="{'dialog-fullscreen':fullscreenable}"
            >
                <div class="dialog-header" v-if="$slots.title || title">
                    <slot name="title">{{title}}</slot>
                    <i class="dialog-fullcreen iconfont" 
                        :class="{
                            'icon-normal':fullscreenable,
                            'icon-max':!fullscreenable
                        }" 
                        v-if="fullscreen" 
                        @click="fullscreenable = !fullscreenable"></i>
                    <i class="dialog-close iconfont icon-close" v-if="headClose" @click="close"></i>
                </div>
                <div class="dialog-body">
                    <slot>{{content}}</slot>
                </div>
                <div class="dialog-footer" v-if="$slots.footer || okText || cancelText">
                    <slot name="footer">
                        <button class="dialog-btn" v-if="okText" @click="ok"><span>{{okText}}</span></button>
                        <button class="dialog-btn" v-if="cancelText" @click="cancel"><span>{{cancelText}}</span></button>
                    </slot>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    name: "veDialog",
    props:{
        value:{
            type: Boolean,
            default: false
        },
        closeable:{
            type: Boolean,
            default: false
        },
        maskhide:{
            type: Boolean,
            default: true
        },
        title:{
            type: String,
            default:""
        },
        headClose:{
            type:Boolean,
            default: true
        },
        okText: String,
        cancelText: String,
        content:{
            type: String,
            default: "这是弹框"
        },
        size:{
            type: Number,
            default: 520
        },
        styles:{
            type:Object
        },
        fullscreen:{
            type: Boolean,
            default: true
        }
    },
    data(){
        return{
            visible: this.value,
            fullscreenable: false
        }
    },
    computed:{
        dialogStyle(){
            let _style = {};
            let widthStyle = {
                width: this.size>100?`${this.size}px`:`${this.size}%`
            }
            let customStyle = this.styles || {};
            return Object.assign(_style,widthStyle, customStyle);
        }
    },
    methods:{
        close(){
            this.visible = false;
            this.$emit("input", false);
            this.$emit('on-cancel')
        },
        maskClose(){
            this.closeable && this.close()
        },
        ok(){
            this.visible = false;
            this.$emit("input", false);
            this.$emit('on-ok')
        },
        cancel(){
            this.close();
        },
        EscClose (e) {
            if (this.visible && this.closable) {
                if (e.keyCode === 27) {
                    this.close()
                }
            }
        },
    },
    mounted(){
        document.addEventListener('keydown', this.EscClose);
    },
    beforeDestroy(){
        document.removeEventListener('keydown', this.EscClose);
    },
    watch:{
        value (val){
            this.visible = val;
        },
        visible(val){
            this.$emit("on-visible-change", val)
        }
    }
}
</script>

dialog.js

import Vue from 'vue';
import Dialog from './modal';

Dialog.newInstace = proper => {
    const _props = proper || {};
    const Instance = new Vue({
        data: Object.assign({}, _props, {
            visible: false,
            size: 416,
            title: "",
            content: "",
            fullscreen: true,
            okText: undefined,
            cancelText: undefined,
            showCancel: false,
            clasealbe:false
        }),
        render(h){
            let footerVNode = [];
            footerVNode.push(h('button', {
                attrs:{
                    class: ['dialog-btn ok-btn'],
                },
                on:{
                    click: this.ok
                }
            }, this.localeOkText));
            if(this.showCancel){
                footerVNode.push(h('button', {
                    attrs:{
                        class: ['dialog-btn','cancel-btn'],
                    },
                    on:{
                        click: this.cancel
                    }
                }, this.localeCancelText))
            }

            let header_render;
            if(this.title){
                header_render = this.iconType?
                h('div',{
                    slot: 'title',
                },[
                    h('i',{
                        class: this.iconTypeCls
                    }),
                    h('span',{
                        domProps:{
                            innerHTML: this.title
                        }
                    })
                ])
                :h('div',{
                    slot:'title',
                    domProps:{
                        innerHTML: this.title
                    }
                });
            }
            let body_render;
            if(this.render){
                body_render = h('div', {},[this.render(h)])
            }else{
                body_render = h('div', {
                    domProps: {
                        innerHTML: this.body
                    }
                })
            }


            return h(Dialog, {
                props: Object.assign({}, _props,{
                    size: this.size,
                    closable: this.closable,
                    fullscreen: this.fullscreen
                }),
                domProps:{
                    value: this.visible
                },
                on:{
                    input: status => {
                        this.visible = status;
                    },
                    "on-cancel": this.cancel
                }
            },[
                header_render,
                body_render,
                h('template', {
                    slot: "footer"
                },footerVNode)
            ])
        },
        computed:{
            localeOkText(){
                if(this.okText){
                    return this.okText
                }else{
                    return "确定"
                }
            },
            localeCancelText(){
                if(this.cancelText){
                    return this.cancelText
                }else{
                    return "取消"
                }
            },
            iconTypeCls(){
                return [
                    'iconfont',
                    `icon-${this.iconType}`,
                    'title-icon',
                    this.iconType
                ]
            }
        },
        methods:{
            cancel(){
                this.$children[0].visible = false;
                this.onCancel();
                this.remove()
            },
            ok(){
                this.$children[0].visible = false;
                this.remove();
                this.onOk();
            },
            remove(){
                setTimeout(() => {
                    this.destroy();
                }, 300);
            },
            destroy(){
                this.$destroy();
                document.body.removeChild(this.$el);
                this.onRemove();
            },
            onOk () {},
            onCancel () {},
            onRemove () {}
        }
    });

    const component = Instance.$mount();
    document.body.appendChild(component.$el);
    const dialog = Instance.$children[0];

    return {
        show(props){
            dialog.$parent.showCancel = props.showCancel;
            dialog.$parent.iconType = props.icon;

            if ('size' in props) {
                dialog.$parent.size = props.size;
            }

            if ('closable' in props) {
                dialog.$parent.closable = props.closable;
            }

            if ('title' in props) {
                dialog.$parent.title = props.title;
            }

            if ('content' in props) {
                dialog.$parent.body = props.content;
            }

            if ('okText' in props) {
                dialog.$parent.okText = props.okText;
            }

            if ('cancelText' in props) {
                dialog.$parent.cancelText = props.cancelText;
            }
            if ('fullscreen' in props) {
                dialog.$parent.fullscreen = props.fullscreen;
            }

            if ('onCancel' in props) {
                dialog.$parent.onCancel = props.onCancel;
            }

            if ('onOk' in props) {
                dialog.$parent.onOk = props.onOk;
            }
            dialog.$parent.onRemove = props.onRemove;
            dialog.visible = true;
        },
        remove(){
            dialog.visible = false;
            dialog.$parent.remove();
        },
        component: dialog
        
    }
}

export default Dialog;

index.js

import './dialog.scss';

import Dialog from './dialog';

let dialogInstance;

function getDialogInstance(render=undefined){
    dialogInstance = dialogInstance || Dialog.newInstace({
        closeable: false,
        render: render
    });

    return dialogInstance;
}

function confirm(opt){
    const render = ('render' in opt)?opt.render:undefined;
    let instance = getDialogInstance(render);

    opt.onRemove = function(){
        dialogInstance = null;
    }
    instance.show(opt);
}

Dialog.info = function(props = {}){
    props.icon = 'info';
    props.showCancel = false;
    props.size = 300;
    return confirm(props)
}
Dialog.success = function(props = {}){
    props.icon = 'success';
    props.showCancel = false;
    props.size = 300;
    return confirm(props)
}
Dialog.warning = function(props = {}){
    props.icon = 'warning';
    props.showCancel = false;
    props.size = 300;
    return confirm(props)
}
Dialog.error = function (props = {}) {
    props.icon = 'error';
    props.showCancel = false;
    props.size = 300;
    return confirm(props);
};
Dialog.confirm = function (props = {}) {
    props.showCancel = true;
    return confirm(props);
};

Dialog.remove = function(){
    if(!dialogInstance){
        return false;
    }
    const instance = getDialogInstance();
    instance.remove();
}

export default Dialog;

dialog.scss


$prefix                     :"dialog";
$zIndex                     :1000;

*{
    padding: 0;
    margin: 0;
}
:root{
    font-size: 12px;
}


.#{$prefix}-mask{
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(#000000, .2);
    z-index: $zIndex;
}
.#{$prefix}{
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: $zIndex + 1;
    .#{$prefix}-main{
        width: 300px;
        background-color: #fff;
        position: absolute;
        top: 20%;
        left: 50%;
        transform: translate(-50%, -20%);
        border-radius: 5px;
        box-shadow: 0 0 20px #999;
        display: flex;
        flex-direction: column;
        max-height: 80%;
        &.dialog-fullscreen{
            top: 0;
            left: 0;
            width: 100vw !important;
            height: 100vh !important;
            transform: none;
            // max-width: 100%;
            max-height: 100%;
        }
        .#{$prefix}-header{
            line-height: 3rem;
            border-bottom: 1px solid #eee;
            box-shadow: 0px 0px 10px #999;
            padding: 0 1rem;
            .title-icon{
                margin-right: .5rem;
                &.info{
                    color: #2196f3;
                }
                &.success{
                    color: #4caf50;
                }
                &.warning{
                    color: #ff9800;
                }
                &.error{
                    color: #f44336;
                }
            }
            span{
                font-weight: 900;
            }
            .#{$prefix}-fullcreen{
                position: absolute;
                top: 0;
                right: 3rem;
                cursor: pointer;
                color: #666;
                &:hover{
                    color: #333;
                }
            }
            .#{$prefix}-close{
                position: absolute;
                top: 0;
                right: 1rem;
                cursor: pointer;
                color: #666;
                &:hover{
                    color: #333;
                }
            }
        }
        .#{$prefix}-body{
            flex: 1;
            overflow: auto;
        }
        .#{$prefix}-footer{
            padding: 1rem 0;
            border-top: 1px solid #eee;
            box-shadow: 0px -1px 10px #999;
            padding: 0 1rem;
            .#{$prefix}-btn{
                float: right;
                margin: .5rem 0 .5rem 1rem;
                background-color: #fff;
                border: none;
                line-height: 2rem;
                padding: 0 .5rem;
                border: 1px solid #eee;
                border-radius: 5px;
                cursor: pointer;
                &:hover{
                    background: #2196f3;
                    color: #fff;
                    border-color: #2196f3;
                    opacity: .75;
                }
                // &:focus{
                    
                // }
                // outline: none;
            }
        }
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值