资讯专栏INFORMATION COLUMN

写一个单例构造的对话框

weknow619 / 2697人阅读

摘要:前言项目中,当需要用户处理事务,又不希望跳转页面以致打断工作流程时,我们会经常使用到对话框去承载相应的操作。虽然用得多,但是很多人其实并不知道怎么去写。饶有兴趣,自己尝试写了一个。

前言

项目中,当需要用户处理事务,又不希望跳转页面以致打断工作流程时,我们会经常使用到对话框去承载相应的操作。虽然用得多,但是很多人其实并不知道怎么去写。饶有兴趣,自己尝试写了一个。

API
参数 说明 类型 默认值
afterClose Modal 完全关闭后的回调 function
cancelText 取消按钮文字 string 取消
closable 是否显示右上角的关闭按钮 boolean true
destroyOnClose 关闭时销毁 Modal boolean false
footer 底部内容,当不需要默认底部按钮时,可以设为 false boolean true
maskClosable 点击蒙层是否允许关闭 boolean true
okText 确认按钮文字 string 确定
title 标题 string|html节点 标题
width 宽度 number 500
zIndex 设置 Modal 的 z-index number 1000
keyboard 是否支持键盘esc关闭 boolean true
onCancel 点击遮罩层或右上角叉或取消按钮的回调 function(e)
onOk 点击确定回调 function(e)
methods
参数 说明 使用形式
set 已覆盖默认的形式,设置新的属性,内部 Object.assign(this.options, newOptions) model.set(newOptions)
open 打开对话框 model.open()
close 关闭对话框 model.close()
destroy 与close的区别在于,会从节点上删除 model.destroy()
代码

对话框全局中使用一个就够了,为了防止生成多个对话框,我们使用单例构造

var Dialog = (function () {
    var instance;
    return function (options) {
        if (!instance) {
            instance = new Modal(options);
        }
        return instance;
    }
})()

这里主要运用到了闭包中的特性

modal.js代码

var Dialog = (function () {
    var instance;
    return function (options) {
        if (!instance) {
            instance = new Modal(options);
        }
        return instance;
    }
})()

class Modal {
    constructor(options) {
        //默认属性
        this.initOptions = {
            title: "标题",
            maskClosable: true,
            header: true,
            footer: true,
            closable: true,
            okText: "确 定",
            cancelText: "取 消",
            destroyOnClose: false,
            keyboard: true,
            zIndex: 1000,
            width: 500,
            afterClose: null
        }
        this.options = Object.assign({}, this.initOptions, options);

        this.instance = document.createElement("div");//节点实例,因为只需要一个模态框,这里设置节点就可以了
        this.mounted = false; //是否挂载在节点上
    }

    //处理模态框的点击事件
    _modalClick(e) {
        var className = e.target.className;
        //匹配类名,例如 带有 class="modal-close" 的元素点击可以关闭模态框
        if (new RegExp("(s|^)modal-close(s|$)").test(className)) {
            this.cancel();   //关闭模态框
        } else if (new RegExp("(s|^)modal-onOk(s|$)").test(className)) {
            this.onOk();     //执行确定按钮的回调
        } else if (new RegExp("(s|^)modal-container(s|$)").test(className)) {
            this.outSideClick(); //模态框外的点击
        }
    }

    //处理键盘ESC关闭
    _escClose(e) {
        var code = e.keyCode;
        if (code === 27) {
            this.cancel();
        }
    }

    //渲染模态框节点
    render() {
        var modal = this.instance;
        modal.style.zIndex = this.options.zIndex;
        modal.className = "modal-container";
        var closeIcon = this.options.closable ? `X` : "";
        var header = this.options.header ?
            (this.options.header === true ?
                `` :
                this.options.header) :
            "";
        var footer = this.options.footer ?
            (this.options.footer === true ?
                `` :
                this.options.footer) :
            "";
        modal.innerHTML = ``;
    }


    //蒙层点击关闭
    outSideClick() {
        if (this.options.maskClosable) {
            this.close();
        }
    }

    //处理监听
    listen() {
        this._modalClick = this._modalClick.bind(this);
        this.instance.addEventListener("click", this._modalClick);
        
        if(this.options.keyboard){
            this._escClose = this._escClose.bind(this);
            window.addEventListener("keyup", this._escClose);
        }
    }

    cancel(){
        if(typeof this.options.onCancel === "function"){
            this.options.onCancel();
        }
        this.close();
    }

    //点击确定回调
    onOk() {
        this
            .options
            .onOkFn();
        this.close();
    }


    /****************** 提供的方法  ********************* */
    //设置属性
    set(options) {
        Object.assign(this.options, options)
        this.render()
    }

    //打开模态框
    open() {
        var modal = this.instance;
        //实例如果没挂载
        if (!this.mounted) {
            this.mounted = true;
            this.render();
            document.body.appendChild(modal);
            this.listen()
        }
        removeClass(modal, "close");
        addClass(modal, "open");
    }

    //关闭模态框
    close() {
        var modal = this.instance
        removeClass(modal, "open");
        addClass(modal, "close");
        if (this.options.destroyOnClose === true) {
            this.destroy();
        }
        if (typeof this.options.afterClose === "function") {
            var afterClose = this.options.afterClose.bind(this);
            setTimeout(afterClose, 0);
        }
    }
    //从节点上移除模态框
    destroy() {
        this.instance.removeEventListener("click", this._modalClick);//移除click监听
        window.removeEventListener("keyup", this._escClose);//移除keyup监听
        document.body.removeChild(this.instance);//移除模态框节点
        this.mounted = false;
    }

}

function hasClass(elements, cName) {
    return !!elements
        .className
        .match(new RegExp("(s|^)" + cName + "(s|$)"));
};
function addClass(elements, cName) {
    if (!hasClass(elements, cName)) {
        elements.className += " " + cName;
    };
};
function removeClass(elements, cName) {
    if (hasClass(elements, cName)) {
        elements.className = elements
            .className
            .replace(new RegExp("(s|^)" + cName + "(s|$)"), "");
    };
};

modal.css

@keyframes openAnimate {
    0% {
        opacity: 0;
    }
    100%{
        opacity: 1;
    }
}

.open{
    display: block !important;
    animation: openAnimate .8s;
}
.close{
    display: none;
}
.modal-container {
    position: fixed;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    background-color: #373737;
    background-color: rgba(0,0,0,.65);
    margin: auto;
    filter: alpha(opacity=50);
    text-align: center;
    font-size: 0;
    white-space: nowrap;
    overflow: auto;
    display: none;
}

.modal-container:after {
    content: "";
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}

.modal {
    display: inline-block;
    vertical-align: middle;
    text-align: left;
    font-size: 14px;
    background-color: #fff;
    border: 0;
    border-radius: 4px;
    background-clip: padding-box;
    box-shadow: 0 4px 12px rgba(0,0,0,.15);
}

.modal-header{
    padding: 16px 24px;
    border-radius: 4px 4px 0 0;
    background: #fff;
    color: rgba(0,0,0,.65);
    border-bottom: 1px solid #e8e8e8;
}
.modal-close{
    float: right;
    cursor: pointer;
}
.modal-content{
    padding: 24px;
    font-size: 14px;
    line-height: 1.5;
    word-wrap: break-word;
    min-height: 200px;
}

.modal-footer {
    border-top: 1px solid #e8e8e8;
    padding: 10px 16px;
    text-align: right;
    border-radius: 0 0 4px 4px;
}

.modal-btn{
    line-height: 32px;
    display: inline-block;
    font-weight: 400;
    text-align: center;
    touch-action: manipulation;
    cursor: pointer;
    background-image: none;
    border: 1px solid transparent;
    white-space: nowrap;
    padding: 0 15px;
    font-size: 14px;
    border-radius: 4px;
    height: 32px;
    user-select: none;
    transition: all .3s cubic-bezier(.645,.045,.355,1);
    position: relative;
    color: rgba(0,0,0,.65);
    background-color: #fff;
    border-color: #d9d9d9;
    cursor: pointer;
}

.modal-btn-primary{
    color: #fff;
    background-color: #1890ff;
    border-color: #1890ff;
}
如何使用



    
        
        
        
        Document
        
    

    
        
        
        
        
        
    

index.js

var config = {
    title: "模态框标题",
    content: "",
    header: true,
    footer: true,
    destroyOnClose: true,
    onOkFn: function () {
        alert("提交成功")
    },
    afterClose: function(){
        alert("已经关闭")
    }
}
var modal = new Dialog(config);
var openBtns = document.querySelectorAll(".open");
openBtns.forEach(function (item, index) {
    item.onclick = function () {
        var option = {
            content: "这是第" + (index + 1) + "个"
        }
        modal.set(option)
        modal.open();
    }

})

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95423.html

相关文章

  • Java基础学习——多线程之单例设计模式(转)

    摘要:总之,选择单例模式就是为了避免不一致状态,避免政出多头。二饿汉式单例饿汉式单例类在类初始化时,已经自行实例化静态工厂方法饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。 概念:  Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例、饿汉式单例。  单例模式有以下特点:  1、单例类只能有一个实例。 ...

    dendoink 评论0 收藏0
  • PHP设计模式之单例模式

    摘要:简介单例模式是指整个应用中类只有一个对象实例的设计模式。它是一种常见的设计模式,在计算机系统中,线程池缓存日志对象对话框打印机数据库操作显卡的驱动程序常被设计成单例。 简介 单例模式是指整个应用中类只有一个对象实例的设计模式。它通常被用来创建对象,确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 它是一种常见的设计模式,在计算机系统中,线程池、缓存、日志对象、对话框、打...

    OnlyLing 评论0 收藏0
  • 常用设计模式——单例模式

    摘要:一单例模式定义单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。技术实现单例模式静态内部类评价使用静态内部类的方式,只有在使用该实例的时候,才去加载静态内部类,从而实现延时加载。 一、单例模式定义:单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应...

    stormgens 评论0 收藏0
  • 面试官:“谈谈Spring中都用到了那些设计模式?”。

    摘要:会一直完善下去,欢迎建议和指导,同时也欢迎中用到了那些设计模式中用到了那些设计模式这两个问题,在面试中比较常见。工厂设计模式使用工厂模式可以通过或创建对象。 我自己总结的Java学习的系统知识点以及面试问题,已经开源,目前已经 41k+ Star。会一直完善下去,欢迎建议和指导,同时也欢迎Star: https://github.com/Snailclimb... JDK 中用到了那...

    Astrian 评论0 收藏0
  • 深入理解单例模式

    摘要:总结我们主要介绍到了以下几种方式实现单例模式饿汉方式线程安全懒汉式非线程安全和关键字线程安全版本懒汉式双重检查加锁版本枚举方式参考设计模式中文版第二版设计模式深入理解单例模式我是一个以架构师为年之内目标的小小白。 初遇设计模式在上个寒假,当时把每个设计模式过了一遍,对设计模式有了一个最初级的了解。这个学期借了几本设计模式的书籍看,听了老师的设计模式课,对设计模式算是有个更进一步的认识。...

    FuisonDesign 评论0 收藏0

发表评论

0条评论

阅读需要支付1元查看
<