基于原生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.js
和modalpugin.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
发表回复