基于原生JS封装的Modal对话框插件的示例代码


Posted in Javascript onSeptember 09, 2020

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

基于原生JS封装的Modal对话框插件的示例代码

创建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
    }

对参数进行处理

基于原生JS封装的Modal对话框插件的示例代码

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'
    }

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

基于原生JS封装的Modal对话框插件的示例代码

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
        }

      })
    },

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

基于原生JS封装的Modal对话框插件的示例代码

基于原生JS封装的Modal对话框插件的示例代码
基于原生JS封装的Modal对话框插件的示例代码

//使用:
基于原生JS封装的Modal对话框插件的示例代码
基于原生JS封装的Modal对话框插件的示例代码

完整代码

//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:

基于原生JS封装的Modal对话框插件的示例代码

github

完整代码github

到此这篇关于基于原生JS封装的Modal对话框插件的示例代码的文章就介绍到这了,更多相关JS封装Modal对话框插件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
利用jQuery实现可以编辑的表格
May 26 Javascript
JavaScript设计模式之外观模式实例
Oct 10 Javascript
javascript制作的cookie封装及使用指南
Jan 02 Javascript
学习javascript面向对象 理解javascript原型和原型链
Jan 04 Javascript
关于vuex的学习实践笔记
Apr 05 Javascript
JavaScript你不知道的一些数组方法
Aug 18 Javascript
JS设计模式之观察者模式实现实时改变页面中金额数的方法
Feb 05 Javascript
通过js动态创建标签,并设置属性方法
Feb 24 Javascript
Array数组对象中的forEach、map、filter及reduce详析
Aug 02 Javascript
angular4笔记系列之内置指令小结
Nov 09 Javascript
小试小程序云开发(小结)
Jun 06 Javascript
详解package.json版本号规则
Aug 01 Javascript
vue监听浏览器原生返回按钮,进行路由转跳操作
Sep 09 #Javascript
JS实现斐波那契数列的五种方式(小结)
Sep 09 #Javascript
JavaScript代码简化技巧实例解析
Sep 09 #Javascript
vue 手机物理监听键+退出提示代码
Sep 09 #Javascript
关于angular引入ng-zorro的问题浅析
Sep 09 #Javascript
关于vue的列表图片选中打钩操作
Sep 09 #Javascript
JavaScript日期库date-fn.js使用方法解析
Sep 09 #Javascript
You might like
PHP学习之PHP变量
2006/10/09 PHP
第五节--克隆
2006/11/16 PHP
XAMPP安装与使用方法详细解析
2013/11/27 PHP
php时间计算相关问题小结
2016/05/09 PHP
CodeIgniter记录错误日志的方法全面总结
2016/05/17 PHP
微信公众平台开发教程③ PHP实现微信公众号支付功能图文详解
2019/04/10 PHP
JavaScript实现重置表单(reset)的方法
2015/04/02 Javascript
浅谈JavaScript for循环 闭包
2016/06/22 Javascript
纯JS实现可拖拽表单的简单实例
2016/09/02 Javascript
JQuery 动态生成Table表格实例代码
2016/12/02 Javascript
前端面试知识点锦集(JavaScript篇)
2016/12/28 Javascript
Angular 输入框实现自定义验证功能
2017/02/19 Javascript
详解React-Native全球化多语言切换工具库react-native-i18n
2017/11/03 Javascript
在vue项目创建的后初始化首次使用stylus安装方法分享
2018/01/25 Javascript
vue-cli3项目展示本地Markdown文件的方法
2019/06/07 Javascript
解决vue watch数据的方法被调用了两次的问题
2020/11/07 Javascript
python创建临时文件夹的方法
2015/07/06 Python
python实现多线程抓取知乎用户
2016/12/12 Python
Python 出现错误TypeError: ‘NoneType’ object is not iterable解决办法
2017/01/12 Python
Python实现将一个大文件按段落分隔为多个小文件的简单操作方法
2017/04/17 Python
使用Python3制作TCP端口扫描器
2017/04/17 Python
Python模块搜索路径代码详解
2018/01/29 Python
Python使用sorted对字典的key或value排序
2018/11/15 Python
scrapy头部修改的方法详解
2020/12/06 Python
Html5 webview元素定位工具的实现
2020/08/07 HTML / CSS
贝尔帐篷精品店:Bell Tent Boutique
2019/06/12 全球购物
Yummie官方网站:塑身衣和衣柜必需品
2019/10/29 全球购物
热爱祖国的演讲稿
2014/05/04 职场文书
公司委托书怎么写
2014/08/02 职场文书
2014年教师节活动总结
2014/08/29 职场文书
解除劳动合同证明书
2014/09/26 职场文书
说谎欺骗人检讨书300字
2014/11/18 职场文书
会计主管岗位职责
2015/04/02 职场文书
优秀范文:《但愿人长久》教学反思3篇
2019/10/24 职场文书
CSS实现章节添加自增序号的方法
2021/06/23 HTML / CSS
详解Python中__new__方法的作用
2022/03/31 Python