基于原生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()执行逻辑

file

创建DOM

//创建DOM结构

creatDom(){

//如果用creatElement插入DOM,每一次动态插入,都会导致DOM的回流,非常消耗性能,所以最外面使用createElement创建,内部使用字符串的方式拼写进去,创建好了之后放到最外层的容器当中,只引起一次回流

let frag = document.createDocumentFragment()

let dpnDialog = document.createElement('div')

dpnDialog.className = 'dpn-dialog'

dpnDialog.innerHTML = `

系统温馨提示

确定

取消

`

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

}

对参数进行处理

file

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 = `

${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)//使用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'

}

基于事件委托处理点击事件

file

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

}

})

},

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

file

file

file

//使用:

file

file

完整代码

//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 = `

${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)//使用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:

file

github

原生html中modal,基于原生JS封装的Modal对话框插件相关推荐

  1. 初探 amaze-vue( 基于vue.js封装的Amaze UI 组件库)

    Amaze UI 是以移动优先(Mobile first)为理念,面向 HTML5 开发的国产优秀组件库.因官方未提供vue.js版本,而且民间一直对vue.js版本的 Amaze UI 组件库呼声很 ...

  2. jBox 2.3基于jquery的最新多功能对话框插件 常见使用问题解答

    jBox 是一款基于 jQuery 的多功能对话框插件,能够实现网站的整体风格效果,给用户一个新的视觉享受. 插件说明 - jBox 是一款基于 jQuery 的多功能对话框插件,能够实现网站的整体风 ...

  3. Vue项目中使用基于pdf.js的vue-pdf插件在pc浏览器下阅览PDF文件

    最近项目中需求为在浏览器上阅览PDF格式的文件,之前没有写过,随即上网查阅,发现大家常使用的为两个插件. 其一是火狐出品的pdf.js,github地址:https://github.com/mozi ...

  4. 基于clamp.js封装vue指令,处理多行文本的溢出

    最近做项目时,遇到了一个需求:要求div里文本在两行显示,div的宽度是固定的,如果溢出的话就显示省略号.单行文本的溢出问题,我们都很熟悉,只要添加以下css属性就ok: overflow: hidd ...

  5. 原生JS封装Ajax插件(同域jsonp跨域)

    2019独角兽企业重金招聘Python工程师标准>>> 抛出一个问题,其实所谓的熟悉原生JS,怎样的程度才是熟悉呢? 最近都在做原生JS熟悉的练习... 用原生Js封装了一个Ajax ...

  6. js 封装ajax方法吗,原生JS封装ajax方法

    jquery框架的ajax方法固然好用,但是假如某天我们的项目不能引入jquery或项目需求很简单,没有很多交互功能,只需要ajax,这时引入jquery库会造成资源浪费,也会显得页面臃肿.这时我们就 ...

  7. Flutter中嵌入Android 原生TextView

    更多文章请查看 flutter从入门 到精通 本篇文章 中写到的是 flutter 调用了Android 原生的 TextView 案例 添加原生组件的流程基本上可以描述为: 1 android 端实 ...

  8. 基于draft.js 和 braft-editor.js文档,自己总结的内容

    我还没有整理,但是应该能帮助到你 * 包含一些文章 * 包含自己的总结 * 包含一些自己的实例,自定义块,自定义行内,删除元素等 分割线 1.一篇文档足矣(无数个文章综合体) https://www. ...

  9. 我开发了一个基于 Egg.js 的后端脚手架

    背景 之前基于 Egg.js 开发了几个项目,发现每个项目中都有配置文件.数据库连接操作.数据模型定义.微信登陆授权处理等功能,而做新项目时总会复制之前的项目来删删改改,有时候在 A 项目中添加了一个 ...

最新文章

  1. 入门 Python GUI 开发的第一个坑
  2. matlab gui创建,Matlab创建GUI
  3. 比特币钱包(3) BIP32 HD钱包之密钥树
  4. CISCO2621 基本配置步骤
  5. PYG教程【四】Node2Vec节点分类及其可视化
  6. 虚拟化关键技术及解决方案
  7. 基于JAVA+SpringMVC+Mybatis+MYSQL的二手电动车交易系统
  8. char *p = new char[256]; delete p; / delete[] p; 哪个对 为什么
  9. GitHub 又又又挂了?
  10. 陆奇知天命,拒绝巨头选 YC
  11. java 读取本地文件_java 读取本地文件实例详解
  12. pygame里面物体闪烁运动_关于“雷氏力学”运动力在空间上积累的一点研究(1)...
  13. 最新消息!OKR周报新模板!
  14. 计算机系统修复命令提示符,win10怎么用命令提示符修复电脑 用命令提示符修复win10电脑的方法...
  15. 规范化理论:候选键的求解理论和算法
  16. 超声波传感器(CHx01) 学习笔记 Ⅳ- 程序移植
  17. 美国80后恶搞希拉里与名人发短信场景
  18. JS中的CommonJS和AMD
  19. Android 屏蔽返回键、菜单键和Home键
  20. 小程序快速生成朋友圈海报分享图

热门文章

  1. 第三章3:elif 语句
  2. Java IO流详尽解析
  3. nodejs与Promise的思想碰撞
  4. 宰相必起于州部,猛将必发于卒伍
  5. hmr webpack 不编译_Webpack HMR 热更新实现原理深入分析
  6. 《AUTOSAR谱系分解(ETAS工具链)》之Ecus
  7. java前端怎么和后端连接_web后端和前端是怎么连接的
  8. 在 Linux 环境下安装 Pycharm
  9. python字符串的索引,字符串的第一和倒数第一个索引
  10. 计算机专业自我总结100字,大学生自我总结100字.pdf