公司需求系列:js封装一个移动端modal框

Created By JishuBao on 2019-04-12 12:38:22
Recently revised in 2019-04-12 17:38:22javascript

 

  欢迎你们来到技术宝的掘金世界,您的star是我写文章最大的动力!GitHub地址           
感受已经好久没写掘金了,多是由于阅读量没多少把,没有动力写,可是我想了想写博客主要仍是记录本身在工做中遇到的问题,主要仍是以本身学习为主,因此仍是写上一写吧哈哈哈。
html

就在今天上午遇到了一个问题,封装一个很简单的弹框,须要作到哪一个页面须要这个弹框,直接引入这个Js文件,执行操做就能够弹出弹框,点击确认弹框消失,由于前面工做中都是之前端框架vue、react为主,已经习惯了那种组件化的开发模式,而且写组件只须要import一下仍是很方便的,可是引入js文件的这种我说实话仍是第一次碰见,毕竟咱们公司尚未作到真正的先后端分离,页面仍是jsp页面,因此我真的也是很心累的。确实难到了我,因此准备写下来本身写好的代码~。万一哪天忘记了还能够再调用这样子,哈哈。大概图是这样,真的很简单~前端

1、理解当即执行函数(function(){})()

以前看了好多代码,都有用到这种函数的写法,可是都没认真的去想为何会这样写,今天开始想学习下jquery的源码,发现jquery也是使用这种方式,用(function(window, undefined){})(window)包裹内部代码,因而进一步的去学习了下。 要理解当即执行函数(function(){})(),先了解些函数的基本概念(函数声明、函数表达式、匿名函数)。vue

函数声明

使用function声明函数,并指定函数名java

function Fn(){
    //coding...
}
复制代码

函数表达式

使用function声明函数,但未指定函数名,将匿名函数赋予一个变量。node

var Fn=function(){
    //coding...
}
复制代码

匿名函数

使用function关键字声明函数,但未指定函数名。匿名函数属于函数表达式,匿名函数有不少做用,赋予一个变量则建立函数,赋予一个事件则成为事件处理程序或建立闭包等。react

function(){
    //coding
}
复制代码

函数声明与函数表达式的区别

  1. 函数声明可再当前做用域下提早调用执行,函数表达式需等执行到函数后,方可执行,不可提早调用。
setFn()
function setFn(){
    //coding
}
//正常,函数声明可提早调用

setFn()
var setFn=function(){
    //coding
}
//报错 setFn未保存对函数的引用,函数调用需放在函数表达式后面
复制代码
  1. 函数表达式可直接在函数后加括号调用。
var setFn=function(){
    console.log('setFn') 
}()
//解析至此 可直接执行调用,即无需再调用,打印出setFn
复制代码

当即执行函数

从上面咱们能够看到 函数表达式写法后面加括号能够无需调用直接执行jquery

var setFn=function(){
    console.log('setFn') 
}()
//解析至此 可直接执行调用,即无需再调用,打印出setFn
复制代码

简化就是var setFn=function(){}(),而咱们的当即执行函数是(function(){})(),当即执行函数(function(){})()能够看出很像函数表达式的调用,但欸什么要加括号呢?若是不加括号:git

function(){
    //coding
}()
//报错,函数须要函数名
复制代码

虽然匿名函数属于函数表达式,但未进行赋值,因此javascript解析时将开头的function看成函数声明,故报错须要函数名es6

当即执行函数里面的函数必须是函数表达式,因此由var setFn = function() {}()能够理解为在匿名函数前加了 = 运算符后,将函数声明转化为函数表达式,因此拿!,+,-,()...等运算符来测试下是否如此。

!function(){
    console.log(1)
}()
// 1
    
+function(){
    console.log(2)
}()
// 2
    
-function(){
    console.log(3)
}()
// 3
    
(function(){
    console.log(4)
})()
// 4
复制代码

因而可知,加运算符确实可将函数声明转化为函数表达式,而之因此使用括号,是由于括号相对其余运算符会更安全,能够减小没必要要的麻烦。

当即执行函数与正常函数传参形式是一致的。

(function(a, b){
    console.log(a + b);
})(1, 2)
// 3
复制代码

(function(){}())这样写的好处是在内部定义的变量不会跟外部的变量有冲突,达到保护内部变量的做用。

2、编写弹框

首先新建mymodal.js文件

(function(window){
	// 使用构造函数方法 声明一个Modal对象
	var Modal=function(ele){
		this.$el=ele;
        this.init();
	}
	// 在Modal的原型上实现close,open,init方法,实现方法的复用
	Modal.prototype.close=function(){
          this.$el.style.display='none';
    }
	Modal.prototype.open=function(){
          this.$el.style.display='block';
    }
	Modal.prototype.init=function(){
          var self=this;
         // 绑定关闭按钮点击事件处理函数,检索全部 带 .close类名 的按钮
          if(this.$el.addEventListener){
              this.$el.addEventListener('click',function(e){
                  e.preventDefault();
                  var target=e.target;
                  var classNames=target.className.split(' ');
                  if(classNames.indexOf('close')!==-1){
                      self.close();
                  }
              },false);
          }else if(this.$el.attachEvent){
              this.$el.attachEvent('onclick',function(e){
                      e=e||window.event;
                  if(e.preventDefault){
                      e.preventDefault();
                  }else{
                      e.returnValue=false;
                  }
                  var target=e.target||e.srcElement;
                  var classNames=target.className.split(' ');
                  if(classNames.indexOf('close')!==-1){
                      self.close();
                  }
              });
          }
      }
})(window)
复制代码

新建mymodal.html页面

<!doctype html>
<html>
	<head>
		<meta charset="utf-8"></meta>
		<title>测试弹框demo</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
	</head>
	<body>
		<div class="container">
			<div class="wrapbutton">
				<div class="button" id="button">点击出现弹框按钮</div>
				<div class="my-modal" id="my-modal" style="display:none;">
					<div class="my-modal-dialog">
						<div class="my-modal-content">今日22:00-15:00都属于系统维护阶段</div>
						<div class="my-modal-controller">
							<div class='my-btn-ok close'>肯定</div>
						</div>
                    </div>
				</div>
			</div>
			<script src="mymodal.js"></script>
			<script type="text/javascript">
				document.getElementById('button').onclick=function(){
					var mymodal=new Modal(document.getElementById('my-modal'));
					mymodal.open();
				}
			</script>
			
		</div>
	</body>
	
	<style>
		*{
			margin:0;
			padding:0;
			box-sizing:border-box;
		}
		html,body{
			width:100%;
			height:100%;
		}
		.container{
			width:100%;
			height:100%;
			display:table;
		}
		.container .wrapbutton{
			display:table-cell;
			vertical-align:middle;
			text-align:center;
		}
		.container .button{
			width:250px;
			height:100px;
			background-color:#1890ff;
			font-size:22px;
			border-radius:10px;
			display:inline-block;
			line-height: 95px;
			box-shadow: 4px 3px 5px -1px #1890ff;
			color:white;
			font-weight:500;
			 
		}
		.my-modal{
			position:fixed;
			top:0;
			bottom:0;
			left:0;
			right:0;
			background-color:rgba(0,0,0,.3);
			transform:all .5s
			z-index:10
		}
		.my-modal-dialog{
			width: 60%;
			min-height: 20%;
			border: 1px solid rgb(153,153,153);
			border-radius: 12px;
			position: absolute;
			background-color: #fff;
			top: 50%;
			left: 50%;
			transform: translate(-50%,-50%);
		}
		.my-modal-content{
			padding: 20px 15px;
			line-height: 1.5em;
		}
		.my-modal-controller{
			border-top: 0.5px solid rgba(0,0,0,.3);
			font-size: 20px;
			height: 50px;
			display: table;
			position: absolute;
			width: 100%;
			bottom: 0;
		}
		.my-btn-ok{
			text-align: center;
			display: table-cell;
			vertical-align: middle;
		}
	</style>
	
</html>
复制代码

浏览器打开mymodal便可看到以下效果:

点击按钮出现modal框,点击肯定modal消失

3、优化结构(写错,勿看)

若是这个弹框只有一个页面用到却是很好弄,可是公司要求这个弹框须要被不少页面引用,若是都加一块div的话不免会出现不少冗杂的代码,也不利于后期维护,可是公司用的是传统的jsp、html不能使用我熟悉的es6语法import 心很累,因此我瞄准了iframe,说实话我面试的时候每天背关于iframe的面试题,即便我根本不知道iframe是什么东西(笑哭),如今就来使用Iframe优化咱们的项目吧!

拆分弹框

  1. 新建modalcomponent.html(名字仍是起的比较组件化的),将弹框相关的代码拆分到这个页面
<!doctype html>
<html>
	<head>
		<meta charset="utf-8"></meta>
		<title>弹框组件</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
	</head>
	<body>
				<div class="my-modal" id="my-modal" style="display:none;">
					<div class="my-modal-dialog">
						<div class="my-modal-content">今日22:00-15:00都属于系统维护阶段</div>
						<div class="my-modal-controller">
							<div class='my-btn-ok close'>肯定</div>
						</div>
                    </div>
				</div>
	</body>
	
	<style>
		.my-modal{
			position:fixed;
			top:0;
			bottom:0;
			left:0;
			right:0;
			background-color:rgba(0,0,0,.3);
	 
			z-index:10
		}
		.my-modal-dialog{
			width: 60%;
			min-height: 20%;
			border: 1px solid rgb(153,153,153);
			border-radius: 12px;
			position: absolute;
			background-color: #fff;
			top: 50%;
			left: 50%;
			transform: translate(-50%,-50%);
		}
		.my-modal-content{
			padding: 20px 15px;
			line-height: 1.5em;
		}
		.my-modal-controller{
			border-top: 0.5px solid rgba(0,0,0,.3);
			font-size: 20px;
			height: 50px;
			display: table;
			position: absolute;
			width: 100%;
			bottom: 0;
		}
		.my-btn-ok{
			text-align: center;
			display: table-cell;
			vertical-align: middle;
		}
	</style>
	
</html>
复制代码
  1. 拆分后的mymodal.html页面
<!doctype html>
<html>
	<head>
		<meta charset="utf-8"></meta>
		<title>测试弹框demo</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
	</head>
	<body>
		<div class="container">
			<div class="wrapbutton">
				<div class="button" id="button">点击出现弹框按钮</div>
			</div>
			<script src="mymodal.js"></script>
			<script type="text/javascript">
				document.getElementById('button').onclick=function(){
					var mymodal=new Modal(document.getElementById('my-modal'));
					mymodal.open();
				}
			</script>
			
		</div>
	</body>
	
	<style>
		*{
			margin:0;
			padding:0;
			box-sizing:border-box;
		}
		html,body{
			width:100%;
			height:100%;
		}
		.container{
			width:100%;
			height:100%;
			display:table;
		}
		.container .wrapbutton{
			display:table-cell;
			vertical-align:middle;
			text-align:center;
		}
		.container .button{
			width:250px;
			height:100px;
			background-color:#1890ff;
			font-size:22px;
			border-radius:10px;
			display:inline-block;
			line-height: 95px;
			box-shadow: 4px 3px 5px -1px #1890ff;
			color:white;
			font-weight:500;
			 
		}
	</style>
	
</html>
复制代码

经过iframe引入modalcomponent组件

在页面引入iframe标签,接下来的要点就是获取Iframe里面的元素了,那获取iframe的元素如何获取呢,让咱们来看下。

<iframe src="modalComponent" name="modalComponent" id="modalComponent"
				width="0" height="0" frameborder="0" scrolling="no" ></iframe>
复制代码

经过百度 咱们发现有如下几种方式

var iframe = document.getElementById("iframe1");
 var iwindow = iframe.contentWindow;
 var idoc = iwindow.document;
        console.log("window",iwindow);//获取iframe的window对象
        console.log("document",idoc);  //获取iframe的document
        console.log("html",idoc.documentElement);//获取iframe的html
        console.log("head",idoc.head);  //获取head
        console.log("body",idoc.body);  //获取body
复制代码

另外更简单的方式是,结合Name属性,经过window提供的frames获取.

console.log(window.frames['ifr1'].window);
console.log(document.getElementById("ifr1").contentWindow);
复制代码

其实window.frames['ifr1']返回的就是window对象,即

window.frames['ifr1']===window
复制代码

当咱们准备用console.log(window.frames['modalComponent'].document.getElementById('my-modal'));获取弹框的Id时,却出现了这个错误!!!

百度了下iframe居然还会跨域 我是对这个Iframe有点心累的!!!

iframe跨域

iframe就是一个隔离沙盒,至关于咱们在一个页面内能够操控不少个标签页同样。若是踩坑的童鞋应该知道,iframe的解决跨域也是颇有套套的。

首先咱们须要明确什么是跨域。

浏览器判断你跨没跨域,主要根据两个点。 一个是你网页的协议(protocol),一个就是你的host是否相同,即,就是url的首部:

window.location.protocol +window.location.host
复制代码

具体的例子就是:

须要强调的是,url首部必须同样,好比:二级域名或者IP地址,都算是跨域.

//域名和域名对应ip, 跨域
http://www.a.com/a.js
http://70.32.92.74/b.js

//统一域名,不一样二级域名。 跨域
http://www.a.com/a.js
http://a.com/b.js
复制代码

对于第二种状况,iframe能够解决 如:

www.foo.com/a.htmlscript.foo.com/b.html 两个文件中分别加上document.domain = ‘foo.com’,指定相同的主域,而后,两个文档就能够进行交互。

//b.html是以iframe的形式嵌套在a.html中

//www.foo.com上的a.html

document.domain = 'foo.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.foo.com/b.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
    var doc = ifr.contentDocument || ifr.contentWindow.document;
    // 在这里操纵b.html
    alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
};
//script.foo.com上的b.html

document.domain = 'foo.com';
复制代码

默认状况下document.domain 是指window.location.hostname. 你能够手动更改,可是最多只能设置为主域名。 一般,主域名就是指不带www的hostname, 好比: foo.com , baidu.com 。 若是,带上www或者其余的前缀,就是二级域名或者多级域名。经过上述设置,相同的domain以后,就能够进行同域的相关操做。 另外还可使用iframe和location.hash,不过因为技术out了,这里就不作介绍了。

说明:本人兴致满满的百度写了好长时间的文章,发现拆分的话使用代码实现不了 可是因为百度了一些时间 也就不删除了 小伙伴只须要看前2章就好了!!

相关文章
相关标签/搜索