基于原生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 "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 "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
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
暂无评论...
更新日志
2024年11月25日
2024年11月25日
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]