基于原生JS封装Modal对话框插件

原生JS封装Modal对话框插件,集体用来学习原理与思维,只有简略的根本框架的实现,可在此基础上增加更多配置项

API配置

        //根本语法    let modal = ModalPlugin({        //提醒的题目信息        title:'零碎提醒',        //内容模板 字符串 /模板字符串/DOM元素对象        template:null,        //自定义按钮信息        buttons:[{            //按钮文字            text:'确定',            click(){                //this:以后实例            }        }]    })    modal.open()//=>关上    modal.close()//=>敞开//基于公布订阅,实现回调函数的监听    modal.on('input/open/close/dragstart/dragmove/dragend',[func])        modal.fire(...)    modal.off(...)

Modal插件外围性能的开发

导出

(function () {    function ModalPlugin() {        return     }    // 浏览器间接导入,这样的办法是裸露到全局的    window.ModalPlugin = ModalPlugin;    //如果还须要反对ES6Module/CommonJS模块导入标准,在react我的项目当中,vue我的项目当中也想用    if (typeof module !== 'undefined' && module.exports !== 'undefined') {//如果module不存在,typeof不会出错,会返回undefined        module.exports = ModalPlugin;//CommonJS标准,只有在webpack环境下才反对    }})()

应用对象和函数创立实例

想应用创建对象的形式new ModalPlugin()创立实例或当做一般函数执行ModalPlugin(),创立实例,须要这样做

(function () {    function ModalPlugin() {        return new init()    }//想应用创建对象的形式`new ModalPlugin()`创立实例或当做一般函数执行`ModalPlugin()`,创立实例,须要这样做    //类的原型: 公共的属性办法    ModalPlugin.prototype = {        constructor: ModalPlugin    }    function init() {}    init.prototype = ModalPlugin.prototype;    // 浏览器间接导入,这样的办法是裸露到全局的    window.ModalPlugin = ModalPlugin;    //如果还须要反对ES6Module/CommonJS模块导入标准,在react我的项目当中,vue我的项目当中也想用    if (typeof module !== 'undefined' && module.exports !== 'undefined') {//如果module不存在,typeof不会出错,会返回undefined        module.exports = ModalPlugin;//CommonJS标准,只有在webpack环境下才反对    }})()

配置项

 //封装插件的时候,须要反对很多配置项,有的配置项不传递有默认值,此时咱们千万不要一个个定义形参,用对象的形式传形参,益处是能够不传,而且能够不必思考程序    function ModalPlugin(options) {        return new init(options)    }//想应用创建对象的形式创立实例new ModalPlugin()或当做一般函数执行也能创立实例ModalPlugin(),须要这样做    ModalPlugin.prototype = {        constructor: ModalPlugin    }    function init(options) {        //接下来将所有的操作全副写在init外面        //参数初始化:传递进来的配置项替换默认的配置项        options = Object.assign({            title:'零碎提醒',            template:null,            frag:true,            buttons:[{                text:'确定',                click(){                }            }]        },options)    }

命令模式init()执行逻辑

创立DOM

//创立DOM构造        creatDom(){            //如果用creatElement插入DOM,每一次动静插入,都会导致DOM的回流,十分耗费性能,所以最里面应用createElement创立,外部应用字符串的形式拼写进去,创立好了之后放到最外层的容器当中,只引起一次回流            let frag = document.createDocumentFragment()            let dpnDialog = document.createElement('div')            dpnDialog.className = 'dpn-dialog'            dpnDialog.innerHTML = `              <div class="dpn-title">                零碎舒适提醒                <i class="dpn-close"></i>              </div>              <div class="dpn-content">                          </div>              <div class="dpn-handle">                <button>确定</button>                <button>勾销</button>              </div>`            frag.appendChild(dpnDialog)            let dpnModel = document.createElement('div')            dpnModel.className = 'dpn-model'            frag.appendChild(dpnModel)            document.body.appendChild(frag)//应用frag只须要往页面中插入一次,缩小回流次数            frag = null            this.dpnDialog = dpnDialog//挂载到实例上,便于其余办法的管制暗藏,并且是公有的实例,            this.dpnModel = dpnModel        }

对参数进行解决

      creatDom() {            let {title, template, buttons} = this.options            //如果用creatElement插入DOM,每一次动静插入,都会导致DOM的回流,十分耗费性能,所以最里面应用createElement创立,外部应用字符串的形式拼写进去,创立好了之后放到最外层的容器当中,只引起一次回流            let frag = document.createDocumentFragment()            let dpnDialog = document.createElement('div')            dpnDialog.className = 'dpn-dialog'            dpnDialog.innerHTML = `              <div class="dpn-title">                ${title}                <i class="dpn-close">X</i>              </div>              <div class="dpn-content">                ${template && typeof template === 'object' && template.nodeType === 1                ? template.outerHTML                : template}              </div>              ${buttons.length > 0                ? `<div class="dpn-handle">                      ${buttons.map((item, index) => {                    return `<button index="${index}">${item.text}</button>`                }).join('')}                   </div>`                : ''            }              `            frag.appendChild(dpnDialog)            let dpnModel = document.createElement('div')            dpnModel.className = 'dpn-model'            frag.appendChild(dpnModel)            document.body.appendChild(frag)//应用frag只须要往页面中插入一次,缩小回流次数            frag = null            this.dpnDialog = dpnDialog//挂载到实例上,便于其余办法的管制暗藏,并且是公有的实例,            this.dpnModel = dpnModel        },

管制暗藏与显示

//管制他显示        open() {            this.dpnDialog.style.display = 'block'            this.dpnModel.style.display = 'block'        },        //管制暗藏        close() {            this.dpnDialog.style.display = 'none'            this.dpnModel.style.display = 'none'        }

基于事件委托解决点击事件

init() {            this.creatDom()            //基于事件委托,实现点击事件的解决            this.dpnDialog.addEventListener('click', (ev)=>{                let target = ev.target,                    {tagName,className}= target                console.log([target])                //点击的敞开按钮                if(tagName==='I'&&className.includes('dpn-close')){                    this.close()                    return                }                //点击的是底部按钮                if(tagName==='BUTTON' && target.parentNode.className.includes('dpn-handle')){                    let index = target.getAttribute('index')                    //让传过来的函数执行,并且函数中的this还必须是以后实例                    let func = this.options.buttons[index]['click']                    if(typeof func==='function'){                        func.call(this)                    }                    return                }            })        },

基于公布订阅实现回调函数的监听(生命周期)


//应用:

残缺代码

//modalplugin.js(function () {    //封装插件的时候,须要反对很多配置项,有的配置项不传递有默认值,此时咱们千万不要一个个定义形参,用对象的形式传形参,益处是能够不穿,而且能够不必思考程序    function ModalPlugin(options) {        return new init(options)    }//想应用创建对象的形式创立实例new ModalPlugin()或当做一般函数执行也能创立实例ModalPlugin(),须要这样做    ModalPlugin.prototype = {        constructor: ModalPlugin,        //相当于大脑,能够管制先干什么在干什么(命令模式)        init() {            //创立DOM构造            this.creatDom()            //基于事件委托,实现点击事件的解决            this.dpnDialog.addEventListener('click', (ev) => {                let target = ev.target,                    {tagName, className} = target                //点击的敞开按钮                if (tagName === 'I' && className.includes('dpn-close')) {                    this.close()                    return                }                //点击的是底部按钮                if (tagName === 'BUTTON' && target.parentNode.className.includes('dpn-handle')) {                    let index = target.getAttribute('index')                    //让传过来的函数执行,并且函数中的this还必须是以后实例                    let func = this.options.buttons[index]['click']                    if (typeof func === 'function') {                        func.call(this)                    }                    return                }            })            this.fire('init')//告诉init办法执行胜利        },        //创立DOM构造        creatDom() {            let {title, template, buttons} = this.options            //如果用creatElement插入DOM,每一次动静插入,都会导致DOM的回流,十分耗费性能,所以最里面应用createElement创立,外部应用字符串的形式拼写进去,创立好了之后放到最外层的容器当中,只引起一次回流            let frag = document.createDocumentFragment()            let dpnDialog = document.createElement('div')            dpnDialog.className = 'dpn-dialog'            dpnDialog.innerHTML = `              <div class="dpn-title">                ${title}                <i class="dpn-close">X</i>              </div>              <div class="dpn-content">                ${template && typeof template === 'object' && template.nodeType === 1                ? template.outerHTML                : template}              </div>              ${buttons.length > 0                ? `<div class="dpn-handle">                      ${buttons.map((item, index) => {                    return `<button index="${index}">${item.text}</button>`                }).join('')}                   </div>`                : ''            }              `            frag.appendChild(dpnDialog)            let dpnModel = document.createElement('div')            dpnModel.className = 'dpn-model'            frag.appendChild(dpnModel)            document.body.appendChild(frag)//应用frag只须要往页面中插入一次,缩小回流次数            frag = null            this.dpnDialog = dpnDialog//挂载到实例上,便于其余办法的管制暗藏,并且是公有的实例,            this.dpnModel = dpnModel        },        //管制他显示        open() {            this.dpnDialog.style.display = 'block'            this.dpnModel.style.display = 'block'            this.fire('open')//告诉open办法执行胜利        },        //管制暗藏        close() {            this.dpnDialog.style.display = 'none'            this.dpnModel.style.display = 'none'            this.fire('close')//告诉close办法执行胜利        },        //on向事件池中订阅办法        on(type, func) {            let arr = this.pond[type]            if(arr.includes(func)) return            arr.push(func)        },        //告诉事件池中的办法执行        fire(type) {            let arr = this.pond[type]            arr.forEach(item => {                if(typeof item ==='function'){                    item.call(this)                }            })        }    }    function init(options) {        //接下来将所有的操作全副写在init外面        //参数初始化:传递进来的配置项替换默认的配置项        options = Object.assign({            title: '零碎提醒',            template: null,            frag: true,            buttons: [{}]        }, options)        //把信息挂载到实例上: 在原型的各个办法中,只有this是实例,都能够调用到这些信息        this.options = options;        this.pond = {            init: [],            close: [],            open: []        }        this.init()    }    init.prototype = ModalPlugin.prototype;    // 浏览器间接导入,这样的办法是裸露到全局的    window.ModalPlugin = ModalPlugin;    //如果还须要反对ES6Module/CommonJS模块导入标准,在react我的项目当中,vue我的项目当中也想用    if (typeof module !== 'undefined' && module.exports !== 'undefined') {//如果module不存在,typeof不会出错,会返回undefined        module.exports = ModalPlugin;//CommonJS标准,只有在webpack环境下才反对    }})()

应用

应用时须要引入modalpugin.jsmodalpugin.css

应用示例1:

//应用:const modal1 = ModalPlugin({    //提醒的题目信息    title: '零碎提醒',    //内容模板 字符串 /模板字符串/DOM元素对象    template: null,    //自定义按钮信息    buttons: [{        //按钮文字        text: '确定',        click() {            //this:以后实例            this.close()        }    }, {        //按钮文字        text: '勾销',        click() {            //this:以后实例            this.close()        },    }]})modal1.on('open',()=>{    console.log('我被关上了1')})modal1.on('open',()=>{    console.log('我被关上了2')})modal1.on('close',()=>{    console.log('我被敞开了')})modal1.open()

应用示例2:

github

残缺代码github