Modal dialog plug-in based on native JS encapsulation

Time:2021-7-28

Encapsulating modal dialog plug-in based on native JS

Native JS encapsulates the modal dialog plug-in, which is used by individuals to learn principles and ideas. There is only a simple implementation of the basic framework, and more configuration items can be added on this basis

API configuration

//Basic grammar
    let modal = ModalPlugin({
        //Prompt title information
        Title: 'system prompt',
        //Content template string / template string / DOM element object
        template:null,
        //Custom button information
        buttons:[{
            //Button text
            Text: 'OK',
            click(){
                //This: current instance
            }
        }]
    })
    Modal. Open() // = > Open
    Modal. Close() // = > close

//Based on publish and subscribe, realize the listening of callback function
    modal.on('input/open/close/dragstart/dragmove/dragend',[func])
		modal.fire(...)
    modal.off(...)

Development of core functions of modal plug-in

export

(function () {
    function ModalPlugin() {
        return 
    }

    //Browser direct import, such a method is exposed to the global
    window.ModalPlugin = ModalPlugin;
    //If you also need to support the es6module / commonjs module import specification, you can also use it in the react project and Vue project
    if (typeof module !== ' undefined' && module.exports !== ' Undefined ') {// if the module does not exist, typeof will not make an error, and undefined will be returned
        module.exports = ModalPlugin;// The commonjs specification is only supported in the webpack environment
    }
})()

Create instances using objects and functions

How do you want to create objectsnew ModalPlugin()Create an instance or execute as a normal functionModalPlugin(), to create an instance, you need to do this

(function () {
    function ModalPlugin() {
        return new init()
    }
//If you want to create an instance by using 'new modalplugin()' or execute 'modalplugin()' as an ordinary function to create an instance, you need to do this

    //Class prototype: public property methods
    ModalPlugin.prototype = {
        constructor: ModalPlugin
    }

    function init() {}
    init.prototype = ModalPlugin.prototype;
    //Browser direct import, such a method is exposed to the global
    window.ModalPlugin = ModalPlugin;
    //If you also need to support the es6module / commonjs module import specification, you can also use it in the react project and Vue project
    if (typeof module !== ' undefined' && module.exports !== ' Undefined ') {// if the module does not exist, typeof will not make an error, and undefined will be returned
        module.exports = ModalPlugin;// The commonjs specification is only supported in the webpack environment
    }
})()

Configuration item

//When encapsulating plug-ins, many configuration items need to be supported. Some configuration items do not pass default values. At this time, we must not define formal parameters one by one and pass them by object. The advantage is that they can be passed without considering the order
    function ModalPlugin(options) {
        return new init(options)
    }
//If you want to create an instance of new modalplugin() by creating an object, or if you can also create an instance of modalplugin() as a normal function, you need to do so
    ModalPlugin.prototype = {
        constructor: ModalPlugin
    }

    function init(options) {
        //Next, write all operations in init
        //Parameter initialization: the configuration item passed in replaces the default configuration item
        options = Object.assign({
            Title: 'system prompt',
            template:null,
            frag:true,
            buttons:[{
                Text: 'OK',
                click(){
                }
            }]
        },options)

    }

Command mode init() execution logic

file

Create DOM

//Create DOM structure
        creatDom(){
            //If you insert the DOM with createElement, every dynamic insertion will lead to the backflow of the DOM, which is very performance consuming. Therefore, the outer part is created with createElement, and the inner part is spelled in the form of string. After creation, it is placed in the outermost container, causing only one backflow
            let frag = document.createDocumentFragment()
            let dpnDialog = document.createElement('div')
            dpnDialog.className = 'dpn-dialog'
            dpnDialog.innerHTML = `
              
                System warm prompt
                
              
              
            
              
              
                determine
                cancel
              `
            frag.appendChild(dpnDialog)

            let dpnModel = document.createElement('div')
            dpnModel.className = 'dpn-model'
            frag.appendChild(dpnModel)
            Document. Body. AppendChild (frag) // you only need to insert frag into the page once to reduce the number of reflow
            frag = null

            This.dpndialog = dpndialog // mount to the instance to facilitate the control and hiding of other methods, and it is a private instance,
            this.dpnModel = dpnModel
        }

Process parameters

file

creatDom() {
            let {title, template, buttons} = this.options
            //If you insert the DOM with createElement, every dynamic insertion will lead to the backflow of the DOM, which is very performance consuming. Therefore, the outer part is created with createElement, and the inner part is spelled in the form of string. After creation, it is placed in the outermost container, causing only one backflow
            let frag = document.createDocumentFragment()
            let dpnDialog = document.createElement('div')
            dpnDialog.className = 'dpn-dialog'
            dpnDialog.innerHTML = `
              
                ${title}
                X
              
              
                ${template && typeof template === 'object' && template.nodeType === 1
                ? template.outerHTML
                : template}
              
              ${buttons.length > 0
                ? `
                      ${buttons.map((item, index) => {
                    return `${item.text}`
                }).join('')}
                   `
                : ''
            }
              `
            frag.appendChild(dpnDialog)

            let dpnModel = document.createElement('div')
            dpnModel.className = 'dpn-model'
            frag.appendChild(dpnModel)
            Document. Body. AppendChild (frag) // you only need to insert frag into the page once to reduce the number of reflow
            frag = null

            This.dpndialog = dpndialog // mount to the instance to facilitate the control and hiding of other methods, and it is a private instance,
            this.dpnModel = dpnModel
        },

Control hide and display

//Control his display
        open() {
            this.dpnDialog.style.display = 'block'
            this.dpnModel.style.display = 'block'
        },
        //Control hiding
        close() {
            this.dpnDialog.style.display = 'none'
            this.dpnModel.style.display = 'none'
        }

Handling click events based on event delegation

file

init() {
            this.creatDom()

            //Based on event delegation, click event processing is realized
            this.dpnDialog.addEventListener('click', (ev)=>{
                let target = ev.target,
                    {tagName,className}= target
                console.log([target])
                //Click the close button of the
                if(tagName==='I'&&className.includes('dpn-close')){
                    this.close()
                    return
                }
                //Click the bottom button
                if(tagName==='BUTTON' && target.parentNode.className.includes('dpn-handle')){
                    let index = target.getAttribute('index')
                    //Let the passed function execute, and this in the function must also be the current instance
                    let func = this.options.buttons[index]['click']
                    if(typeof func==='function'){
                        func.call(this)
                    }
                    return
                }

            })
        },

Monitoring of callback function based on publish subscribe (life cycle)

file

file
file

//Use:
file
file

Complete code

//modalplugin.js
(function () {
    //When encapsulating plug-ins, many configuration items need to be supported. Some configuration items do not pass default values. At this time, we must not define formal parameters one by one and pass them by object. The advantage is that we can not wear them and do not need to consider the order
    function ModalPlugin(options) {
        return new init(options)
    }

//If you want to create an instance of new modalplugin() by creating an object, or if you can also create an instance of modalplugin() as a normal function, you need to do so
    ModalPlugin.prototype = {
        constructor: ModalPlugin,
        //Equivalent to the brain, which can control what to do first and what to do (command mode)
        init() {
            //Create DOM structure
            this.creatDom()

            //Based on event delegation, click event processing is realized
            this.dpnDialog.addEventListener('click', (ev) => {
                let target = ev.target,
                    {tagName, className} = target
                //Click the close button of the
                if (tagName === 'I' && className.includes('dpn-close')) {
                    this.close()
                    return
                }
                //Click the bottom button
                if (tagName === 'BUTTON' && target.parentNode.className.includes('dpn-handle')) {
                    let index = target.getAttribute('index')
                    //Let the passed function execute, and this in the function must also be the current instance
                    let func = this.options.buttons[index]['click']
                    if (typeof func === 'function') {
                        func.call(this)
                    }
                    return
                }
            })
            This. Fire ('init ') // notify the init method of successful execution
        },
        //Create DOM structure
        creatDom() {
            let {title, template, buttons} = this.options
            //If you insert the DOM with createElement, every dynamic insertion will lead to the backflow of the DOM, which is very performance consuming. Therefore, the outer part is created with createElement, and the inner part is spelled in the form of string. After creation, it is placed in the outermost container, causing only one backflow
            let frag = document.createDocumentFragment()
            let dpnDialog = document.createElement('div')
            dpnDialog.className = 'dpn-dialog'
            dpnDialog.innerHTML = `
              
                ${title}
                X
              
              
                ${template && typeof template === 'object' && template.nodeType === 1
                ? template.outerHTML
                : template}
              
              ${buttons.length > 0
                ? `
                      ${buttons.map((item, index) => {
                    return `${item.text}`
                }).join('')}
                   `
                : ''
            }
              `
            frag.appendChild(dpnDialog)

            let dpnModel = document.createElement('div')
            dpnModel.className = 'dpn-model'
            frag.appendChild(dpnModel)
            Document. Body. AppendChild (frag) // you only need to insert frag into the page once to reduce the number of reflow
            frag = null

            This.dpndialog = dpndialog // mount to the instance to facilitate the control and hiding of other methods, and it is a private instance,
            this.dpnModel = dpnModel
        },
        //Control his display
        open() {
            this.dpnDialog.style.display = 'block'
            this.dpnModel.style.display = 'block'
            This. Fire ('open ') // notify that the open method is executed successfully
        },
        //Control hiding
        close() {
            this.dpnDialog.style.display = 'none'
            this.dpnModel.style.display = 'none'
            This. Fire ('close ') // notify the close method of successful execution
        },
        //On subscribes to the event pool
        on(type, func) {
            let arr = this.pond[type]
            if(arr.includes(func)) return
            arr.push(func)
        },
        //Notifies method execution in the event pool
        fire(type) {
            let arr = this.pond[type]
            arr.forEach(item => {
                if(typeof item ==='function'){
                    item.call(this)
                }
            })
        }

    }

    function init(options) {
        //Next, write all operations in init
        //Parameter initialization: the configuration item passed in replaces the default configuration item
        options = Object.assign({
            Title: 'system prompt',
            template: null,
            frag: true,
            buttons: [{}]
        }, options)
        //Mount the information on the instance: in each method of the prototype, you can call this information as long as this is an instance
        this.options = options;
        this.pond = {
            init: [],
            close: [],
            open: []
        }
        this.init()
    }

    init.prototype = ModalPlugin.prototype;
    //Browser direct import, such a method is exposed to the global
    window.ModalPlugin = ModalPlugin;
    //If you also need to support the es6module / commonjs module import specification, you can also use it in the react project and Vue project
    if (typeof module !== ' undefined' && module.exports !== ' Undefined ') {// if the module does not exist, typeof will not make an error, and undefined will be returned
        module.exports = ModalPlugin;// The commonjs specification is only supported in the webpack environment
    }
})()

use

It needs to be introduced during usemodalpugin.jsandmodalpugin.css

Use example 1:

//Use:
const modal1 = ModalPlugin({
    //Prompt title information
    Title: 'system prompt',
    //Content template string / template string / DOM element object
    template: null,
    //Custom button information
    buttons: [{
        //Button text
        Text: 'OK',
        click() {
            //This: current instance
            this.close()
        }
    }, {
        //Button text
        Text: 'Cancel',
        click() {
            //This: current instance
            this.close()
        },

    }]
})
modal1.on('open',()=>{
    Console.log ('I was opened 1 ')
})
modal1.on('open',()=>{
    Console.log ('I was opened 2 ')
})
modal1.on('close',()=>{
    Console.log ('I'm closed ')
})
modal1.open()

Use example 2:
file

github

Complete codegithub