您的位置:首页 > 其它

弹出层插件的编写-layer(跨iframe传值回调)

2014-12-08 09:46 162 查看
弹出层(layer)在往上有非常多,这里为什么我要把它的实现提出来,原因有以下2点:

1、写这篇文章也算是我博客的一个开端,他们都说:“不写博客成不了大神”--

2、我见过的弹出层中都基本没有处理跨iframe传值回调,或者说不是真正意义上的回调函数。

3、一个layer10K左右就可以完成的功能,非得引用一个jqueryEasyUI、jquery等等的方式,都是我不能接受的。



一个独立的插件应该尽量减少依赖,这也是设计模式中追求的解耦与减少依赖。(layer去依赖某种库或多个库,不是一个很好的选择。)





先说说调用方式:插件做出来是让人使用的,我觉得从最终的展现形式入手,能让人更直观的了解这个插件是干嘛的。以及它的优点。

演示代码中我仅仅演示了Iframe弹出层的方式,主要就是看它的回调函数。其它方式,可以在源码中自己查看,稍后将放出源码。



调用方式Code:

<inputtype="button"onclick="iframe0()"value="iframe层,默认无底部"/>
<textareaid="callBox"style="height:200px"></textarea>
functioniframe0(){
layer.win("回调函数的演示","callback.htm",function(data){
document.getElementById("callBox").value+=data+"\r\n";
})
}


上面代码是在index.html页面中的代码,这种场景很多,(比如:订单页面里,需要选择部门的数据,往往会把部门的数据做成一个单独的页面,通过弹出层调用之后选择,然后返回对应的数据)

layer.win是弹出iframe的方式,参数1为弹出层的标题(这个参数其实非常灵活),参数2一看就是一个页面的url,这里设置为callback.html。参数3:这个参数很关键了。它是一个真正意义上的回调函数,也就是当callback.html选择数据返回之后执行的代码。文字比较抽象,还是看代码。



<htmlxmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<scripttype="text/javascript">
functioncall(){
vartext=document.getElementById("v1").value;
top.layer.callData(location.href,text);
}
</script>
</head>
<body>
<h1>注意:这里是在另外一个页面内</h1>
<inputtype="text"id="v1"/>
<inputtype="button"value="触发回调函数,真正的父子页面传值"onclick="call()"/>
</body>
</html>


会前端的朋友都能看懂这段代码,非常简单。当点击按钮时:执行了call这个函数,函数内首先获取id为v1的input值,赋值给text变量。然后调用top.layer.callData(location.href,text)

参数1,location.href即当前的url,这个参数是固定的,不会更改的。参数2text,就是刚刚获取到的值。

当调用这个方法时:就会执行上面调用layer.win里的回调函数,这是如何办到的,这应该是我们最关心的话题。

我见过许国其它弹出层的处理方式:

functioncall(){
vartext=document.getElementById("v1").value;
parent.document.getElementById("callBox").value=text;
}

许多弹出层都是这样的处理方式,或者说直接parent.xxx(text),xxx即是父页面的一个函数。原理就是通过parent等方式去定位调用之前的页面,然后直接访问其页面的元素或者方法。

那么:这样做到底有什么问题?可以这样说,这种设计违背了设计模式的很多原则,别看javascript是弱类型语言。其实它很强大!--

那到底哪里违背了?假设我们还是以上面的例子说明:

订单页面里,需要选择部门的数据,当我们选择数据之后执行call时去调用订单页面的,如:parent.document.getElementById("Order-Department").value=data;

单单看上面的代码,貌似也没有什么问题

现在我又有另外一个页面User.html(用户设置页面),同样也需要调用选择部门的页面,首先:我不可能去重写一个部门页面,因为它已经存在了,如果去重写一个,这......我也不好说什么了,如果不重写,那么我们还是调用先前的部门页面,看会发生什么事情。代码可能就会变成这样了:

functioncall(){
vartext=document.getElementById("v1").value;
if(调用页面==部门页面){
<strong>parent.document.getElementById("Order-<spanleft-pos="0|6"right-pos="0|6"space="">Department</span>").value=text;</strong>
}
	elseif(调用页面==用户页面){
	<strong>parent.document.getElementById("User-<spanleft-pos="0|6"right-pos="0|6"space=""><spanstyle="background-color:rgb(240,240,240);">Department</span></span>").value=text;</strong>
}
}

OK,上面的列子是很常用,很现实的一个例子,如果你是Web系统的开发人员,这种问题基本是不可能不遇到。

很明显:上面的列子违背了太多原则:开放封闭....单一职责原则.......假设还有其它n个页面需要调用到部门选择!假设某天用户页面上的input换了个id!....自己可以想象下!

好了,现在我们回到如何解决这个问题,也就是layer中如何来实现这个真正意义上的回调函数的地方。

翻看源码时你会发现:在调用layer.win方法时,它的第三个参数,也就是回调函数,以这样的代码形式在js中进行了处理:

this.win=function(parameter,src,callback){
if(typeof(parameter)=="object"){
layerobj.init(parameter);
}
else{
layerobj.config.title=parameter;
layerobj.config.iframe.src=src;
layerobj.config.iframe.success=callback;
}
if(layerobj.config.iframe.success){
window["layergofunc"+layerobj.config.id]=layerobj.config.iframe.success;
}
layerobj.config.type=2;
layerobj.config.btns.count=0;
layerobj.config.oframe.foot=false;
layerobj.run();
returnlayerobj;
}


第三个参数callback以window["layergofunc"+layerobj.config.id]=layerobj.config.iframe.success的形式进行了保存。它给窗口注册了一个对象,对象名称是一个字符串+时间戳的方式(layerobj.config.id实际是一个时间戳)。

而当回调页面执行parent.layer.callData(location.href,text);时,为什么有一个固定的参数location.href。这个我们参考callData方法,看看它干了什么事情:

layer.callData=function(layerid){
if(layerid&&layerid.indexOf("http:")!=-1){
layerid=arguments[0].substring(arguments[0].indexOf("layer-id"),arguments[0].length).split("&")[0].split("=")[1];
}
vartemparguments=[].slice.apply(arguments);
vartemparray=[];
if(temparguments.length>1){
temparray=temparguments.slice(1,temparguments.length);
}
window["layergofunc"+layerid](temparray);
};

首先获取了layerid,通过解析了location.href,这里可以猜得到,在调用win方式时,我们为要调用的页面动态的加了一个参数,键值为layer-id。这里通过获取到这个id,然后重新执行了在win方式时注册的window对象。当执行到最后一句代码window["layergofunc"+layerid](temparray);时,实际上就执行了:function(data){document.getElementById("callBox").value+=
data+"\r\n";}这个匿名回调函数。



刚写博文,风格不好,思路也比较乱。不知道有没有解释清楚iframe传值原理。源码我已经提供了下载。这个layer还有很多其它的功能,如果有人有时间做做美化之类的,用它在实际项目中使用来代替模态窗口是个非常不错的选择。首先它小巧,遵循了许多设计上的原则!欢迎留言批判!!!



纯js弹出层附测试demo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: