javascript 禁止事件_如何使用JavaScript构建模态框插件

作为一位Web开发人员而言,模态框(Modal)并不会陌生。就我个人而言,我更为熟悉的是怎么通过CSS来编写一个模态框以及怎么通过CSS给模态框添加一些动效。正好最近工作中也和Modal框杠上了。另外想更好的设计一个模态框用来满足业务需求的普遍性和实用性,甚至是达到可配置性。所以一直在探究模态框相关的知识,能很好的了解如何使用原生的JavaScript来构建一个可用的模态框插件,另外为以后如何使用Vue构建更为灵活的模态框组件打下坚实的基础,或者你也正在加强JavaScript的学习和实战,欢迎继续往下阅读,或许对你有所帮助。

模态框是什么

模态框在前端组件中是一个非常常见的组件。其位于Web应用程序主窗口之上的一个元素。他创建了一个新的模式,该模式禁止用户操作应用程序的主窗口,但它以弹窗的模式在应用程序主窗口之上显示。用户可以在返回应用程序主窗口之前与弹框进行交互操作。

模态框的设计,如果设计或执行不好将会影响主链路的操作,防碍任务的完成。为了确保不影响主链路的操作,一个模态框至少应该包括下面内容:

535288c676ee5bf889fce4094b1479a5.png

一个优秀的Modal框主要包含的部分有:

  • 模态框的蒙层:modal-overlay
  • 模态框头部:modal-header
  • 模态框主体:modal-body
  • 模态框脚部:modal-footer
  • 关闭按钮:modal-close

刚才也提到过,模态框毕竟是在应用程序主窗口上显示,所以需要给用户提供关闭模态框的途径。常见的方式有:

  • 取消按钮
  • 关闭按钮
  • ECS键
  • 点击模态框窗体外的区域关闭模态框

因此,我们要设计一个模态框,也需要考虑这些因素。

构建模态框插件

接下来,我们来看看怎么使用原生的JavaScript来构建一个模态框插件。通过这个学习你将掌握或需要掌握以下几个知识点:

  • CSS的transition或animation相关知识点
  • JavaScript DOM操作相关知识点
  • JavaScript 构造器和构造函数
  • JavaScript 事件监听
  • JavaScript 函数

如果你是一个初学者,还是值得花一点时间阅读该文,如果你是位JS大神,欢迎您拍正文章中的不足。

选择设计模式

首先要确定设计模态弹出框的结构并选择一个设计模式。我们的目的是要创建一个模态弹出框,并且可以真正的运用于我们的项目中。这里将会用到闭包相关的知识,因为闭包可以用来创建一个私有域,可以在其中控制提供哪些数据:

// 创建一个立即调用的函数表达式来包装我们的代码(function() { var privateVar = "在控制台中console.log找不到我"}());

我们想为插件添加一个构造函数方法,并将其公开。IIFE 是全局的,因此this的关键词指向的是window。让我们使用this将构造函数附加到全局作用域:

// 创建一个立即调用的函数表达式来包装我们的代码(function(){ // 定义构造器 this.Modal = function () { }}())

我们将Modal变量指向一个函数,从而创建一个函数对象,现在我们可以用new关键词实例化它,如下所示:

var myModal = new Modal()console.log(myModal) // => Object {}

上面的代码创建了一个对象的新实例。不幸的是,我们的对象在这一点上并没有做什么,所以接下来给这个对象加点其他的东西。

有关于闭包更多的知识点可以阅读下面相关文章:

  • JavaScript 闭包
  • 学习Javascript闭包
  • 闭包(Closures)
  • 解释 JavaScript 的作用域和闭包
  • JavaScript闭包初探
  • 征服 JavaScript 面试:什么是闭包?
  • 理解JAVASCRIPT的闭包
  • 我从没理解过 JavaScript 闭包
  • 从JavaScript闭包函数的undefined形参说起

选项(Options)

回顾一下我们的需求,我们首要的任务是允许用户自定义选项(options)。实现这一点的方法就是创建一组默认的选项,然后将其与用户提供的对象合并。

(function(){ // 定义构造函数 this.Modal = function () { // 创建引用的全局元素 this.closeButton = null; // 关闭按钮 this.modal = null; // 模态弹出框 this.overlay = null; //模态弹出框蒙层 // 自定义默认选项 var defaults = { className: 'fade-and-drop', closeButton: true, content: '', maxWidth: 600, minWidth: 280, overlay: true } // 通过扩展arguments中传递的缺省值来创建选项 if (arguments[0] && typeof arguments[0] === 'object') { this.options = extendDefaults(defaults, arguments[0]) } } // 使用用户选扩展默认值的方法 function extendDefaults(source, properties) { var property; for (property in properties) { if (properties.hasOwnProperty(property)) { source[property] = properties[property] } } return source }}())

首先,创建了被引用的全局元素。这些都很重要,这样一来就可以在插件的任何地方引用Modal。接下来,我们添加了一个默认(defaults)选项对象。如果用户不提供选项(options),就会使用默认选项;如果用户提供了就会覆盖默认选项。那么我们怎么知道用户有没有提供选项呢?这里的关键是arguments对象。这是每个函数内部的一个神奇对象,它包含通过参数传递给它的所有东西的数组。因为我们只期望一个参数,一个包含插件设置的对象,所以我们检查以确保arguments[0],并且它确实是一个对象。

如果条件达得到,就会使用extendDefaults私有域的方法合并这两个对象。extendDefaults接受一个对象,将会遍历它的属性(properties),如果不是其内部属性(hasOwnProperty),就将它分配给源对象(source)。我们现在可以配置我们插件和选项对象。

var myModal = new Modal({ content: 'Howdy', maxWidth: 600})

这个时候在控制台中打印出myModal,其结果如下图所示:

ee10c0258dcebc1c766aa3ba0da39d85.png

为了提供一个公共主法,可以将它附加到Modal对象的原型上(prototype)。当你向对象的原型中添加方法时,每个新实例共享相同的方法,而不是为每个实例创建新方法。这在性能上也具有较大的优势,除非有多级子类化,不然在这种子类化中,遍历原型链会抵消性能提升。我们还添加了注释,并对组件进行了结构化。这样我们就有三个部分:构造函数公共方法私有方法

// 创建一个立即调用的函数表达式来包装我们的代码(function(){ // 定义构造函数 this.Modal = function () { // 创建引用的全局元素 this.closeButton = null; // 关闭按钮 this.modal = null; // 模态弹出框 this.overlay = null; //模态弹出框蒙层 // 自定义默认选项 var defaults = { className: 'fade-and-drop', closeButton: true, content: '', maxWidth: 600, minWidth: 280, overlay: true } // 通过扩展arguments中传递的缺省值来创建选项 if (arguments[0] && typeof arguments[0] === 'object') { this.options = extendDefaults(defaults, arguments[0]) } // 公用方法 Modal.prototype.open = function() { // open方法的对应的代码 } // 私有方法 } // 使用用户选扩展默认值的方法 function extendDefaults(source, properties) { var property; for (property in properties) { if (properties.hasOwnProperty(property)) { source[property] = properties[property] } } return source }}());var myModal = new Modal({ content: 'Howdy', maxWidth: 600})console.log(myModal)

它不做任何功能性的工作,但是它保持了所有内容的组织性和可读性。

有关于函数中的arguments更多的介绍可以阅读下面相关文章:

  • Arguments 对象
  • ES6中Arguments和Parameters用法解析
  • JavaScript 函数参数-Arguments(实参)对象

有关于构造函数相关的知识可以阅读下面相关文章:

  • 详解JavaScript构造器
  • 构造方法
  • 构造函数的继承
  • 构造函数与 new 命令

核心功能

现在我们对模态框的插件架构有了一定的了解,它包括了:构造函数选项公共方法。但它还不能做什么?接下来我们就要给他们添加相应的核心功能。所以我们再来看看,一个模态框应该做什么:

  • 构建一个模态元素并将其添加到页面中
  • 将选项(options)中的className指定一个类名,并将其添加到模态元素中
  • 如果选项中的closeButton为true,则添加关闭按钮
  • 如果选项中的content是 HTML 字符串,则将其设置为模态元素中的内容
  • 如果选项中的content是domNode,则将其内部内容设置为模态元素的内容
  • 分别设置模态的maxWidth和minWidth
  • 如果选项中的overlay为true,则给模态框添加一个蒙层
  • 当模态框显示时,添加一个scotch-open类名,可以在 CSS 中使用它来定义一个open状态
  • 当模态框关闭时,删除scotch-open类名
  • 如果模态框的高度超过视窗的高度,还可以添加一个scotch-anchored类,这样就可以处理这个场景的样式展示

构建自己的模态框

接下来,我们创建一个私人的方法,使用我们自己定义的选项来构建一个模态框:

function buildOut() { var content, contentHolder, docFrag; // 如果内容是HTML是字符串,则追加HTML字符串;如果内容是domNode,则追加其内容 if (typeof this.options.content === 'string') { content = this.options.content } else { content = this.options.content.innerHTML } // 创建一个DocumentFragment docFrag = document.createDocumentFragment() // 创建modal元素 this.modal = document.createElement('div') this.modal.className = 'modal' + this.options.className this.modal.style.minWidth = this.options.minWidth + 'px' this.modal.style.maxWidth = this.options.maxWidth + 'px' // 如果closeButton的值为true,添加close按钮 if (this.options.closeButton === true) { this.closeButton = document.createElement('button') this.closeButton.className = 'modal-close close-button' this.closeButton.innerHTML = 'x' this.modal.appendChild(this.closeButton) } // 如果overlay的值为true,添加蒙层 if (this.options.overlay === true) { this.overlay = document.createElement('div') this.overlay.className = 'modal-overlay' + this.options.className docFrag.appendChild(this.overlay) } // 创建内容区域,并添加到modal中 contentHolder = document.createElement('div') contentHolder.className = 'modal-content' contentHolder.innerHTML = content this.modal.appendChild(contentHolder) // 把modal插到DocumentFragment中 docFrag.appendChild(this.modal) // 把DocumentFragment插到body中 document.body.appendChild(docFrag)}

首先获取目标内容并创建一个DcoumentFragment(文档片段)。文档片段用于构造DOM外部的DOM元素集合,并用于累计地向DOM添加我们构建的内容。如果content是字符串,则将内容变量设置为options值;如果我们的content是domNode,我们通过innerHTML将内容变量设置为它的内部HTML。

接下来,我们创建modal元素,并向其添加className和minWidth、maxWidth样式。同时使用默认的modal类来创建模态框的初始样式。然后,基于options的值,有条件地以相同的方式创建关闭按钮和模态框的蒙层。

最后,我们将content添加到一个变量为contentHolder的div元素中,并将其插入到modal元素中。再把modal元素添加到DocumentFragment中,然后把DocumentFragment插入到body中(插入到

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值