iframe 使用相关

一直有个认知就是最好不要用iframe,这么多年也没用过几次。最近一个项目因为一些原因需要用到这个,而且需要实现父子页面间互相通信,这可难住宝宝了。好在办法总比困难多,最后用一种不友好的方式解决了。

背景:

需要实现的是一个类似[个人中心]里面弹出一个问卷,当用户答完要自动关闭弹窗。

因为这个问卷是后期加入的,所以另起了一个 Vue 项目,做的也是异常的复杂(下次再说吧),在服务器上也是放在不同的位置。

问题来了:因为弹窗是通过js动态加载上去的,而iframe里面的内容又在另一个位置。父页面无法知道子页面什么时候答完了,子页面也无法操作父页面直接关闭。

烂方法:

因为时间紧任务重,没有想到什么好方法,于是我就把弹窗的背景遮罩放在了父页面,当点击遮罩会提示是否退出答题,然后把答案做本地缓存,下次用户进入时再继续答题。

槽点就是当用户真的答完题了,我也这么提示,就显得一点不友好了,体验太差了。

认识iframe

iframe具有自己的属性和方法,主要如下:

frameborder 边框,默认为1,0表示无边框(设为0可以取消内部滚动条)
height/width 宽高,单位是px
marginheight/marginwidth 框架内容到框架的边距,单位是px
name 框架的名称
src 嵌套页面的URL地址
scrolling 是否允许滚动

获取iframe内部的内容:

contentWindow 访问iframe元素所包含的HTML页面的window对象
contentDocument 访问iframe元素所包含的HTML页面的document对象
window.frames[‘name’]

window.parent 从框架中引用它的父框架的window
window.top 最顶级容器的window对象

防止自己的网页被别人当成iframe加载

if(window!=window.top){
window.top.location.href=correctUrl;
}

大杀器:postMessage

记得是有这么个东西,但是一直没细看是怎么用的。抽出空来的时候看了下一个前辈写的教程 《html5 postMessage解决跨域、跨窗口消息传递》,讲解的很详细,还有非常好的demo,真是贴心。

试了一下,连360浏览器的兼容模式下[IE11]都可以正常关闭弹窗,棒棒哒。

postMessage是HTML5引入的一个API,可以实现跨域通信。

信息发送方

window.postMessage()方法被调用时,会在所有页面脚本执行完毕之后向目标窗口派发一个MessageEvent消息。

window.postMessage(message,targetOrigin,[transfer]);
message:要发送到其他窗口的数据
targetOrigin:指定可以接收数据的源,如果是*表示无限制
transfer:是一个可选的参数,随message一起发送

信息接收方

window.addEventListener(“message”, receiveMessage, false);

message:必须是这个,不能改成别的
receiveMessage:接收数据的方法

安全问题

为了安全,在接收的时候要判断一下来源

双向通信

postMessage 支持双向通信,既支持父页面传给子页面,也支持子页面传给父页面

if(e.source!=window.parent) return;

上代码:

子页面js

//当答题完毕后出现提示成功之后:
window.parent.postMessage('close',*);
//最好不要用*,设置具体的接收页面地址

父页面js

//如果用户不答题直接关闭或者答一半误点关闭
$(function(){
getStatus();//判断状态
$('#qsIframe').click(function () {
var close = window.confirm('您确定要关闭问卷吗,如未作答完毕,下次需要重新作答!')
if(close){
$('#qsIframe').hide()
}else{
return
}
})
})
//先判断这个用户状态是否已经答过
function getStatus() {
$.ajax({
url: "",
dataType: 'jsonp',
data: '',
jsonp: 'callback',
success: function (res) {
if (res.data.isNeed == 1) {
appendIframe();
} else {
return
}
}
});
}
// 在父页面插入子页面
function appendIframe(){
var sUserAgent = navigator.userAgent;
var isWin = (navigator.platform == "Win32") || (navigator.platform == "Windows");
var isMac = (navigator.platform == "Mac68K") || (navigator.platform == "MacPPC") || (navigator.platform == "Macintosh") || (navigator.platform == "MacIntel");
var ifr = document.createElement('iframe');
ifr.id = "questionnaire";
ifr.src = 'xxx.com';
//在不同系统上面,iframe会有不同宽度的滚动条
if (isMac){
ifr.width = "850";
}else{
ifr.width = "867";
}
ifr.frameborder = "0";
ifr.border=0;
ifr.height = window.innerHeight-50;
ifr.align = "center";
//插入页面
$("#qsIframe").appendChild(ifr).addClass('showModal');
}
//重头戏postMessage来了
window.addEventListener('message', function (e) {
if (e.data == 'close') {
$('#qsIframe').hide();
} else {
return
}
}, false);

message不能替换成其他参数,
e就是event,e.data——传递过来的数据,e. source——发送消息的窗口对象,e.origin——发送消息的源


总结

很简单啊,有木有。几行代码解决了大问题,体验更优雅,就酱。

参考: