探索Iframe
本文目的:
Iframe简单使用
Iframe跨域
Iframe常见问题
一.Iframe基本Dom以及常用属性和常用事件
1.DOM:
2.常用属性:
和平时使用的DOM标签类似,样式之类的还是建议用class吧,统一起来方便管理。
更多属性看:http://www.runoob.com/tags/ta...
3.常用事件:
一般用这个就够了
onload:当文档加载时运行脚本
document.querySelector('#Yiframe').onload = function(event){
console.log('onload',event);
}
二.JS动态新增并插入Iframe
和平时新增DOM标签一样即可。
var iframe = document.createElement('iframe');
iframe.src = url;
iframe.id = "Yiframe";
iframe.style="height: 100%;width: 100%;border: 0;";
$('.content').append(iframe);
三.iframe与父页面互动
1.注意事项
(1). 必须是在两者同域的情况下才能进行数据交互。
(2). 中间无论嵌套几次iframe,只要其中一个iframe与上级或者上上级同域,两者之前就能进行相互调用
2.实现方案(同域)
(1).父页面获取子页面
document.querySelector('#XXXX').contentWindow
window.frames[x]
可以获取到iframe内的window对象,包括iframe内自行声明的全局方法等。
window.frames注意事项:
该属性返回窗口中所有命名的框架(
直接打印window.frames不是数组对象。
frames.length 来获取框架的数量。
可以通过window.frames[数字]直接获取iframe内的window对象。
(2).子页面获取父页面
window.parent
可以获取到父页面的window对象,包括父页面内自行声明的全局方法等。
3.跨域(未跨主域)
(1).尝试。
打印 document.querySelector('#XXXX').contentWindow 和 window.parent 可以看到里面的属性和方法(第一层/第二层)。
但关键数据和方法会被和谐。
(2).修改document.domain实现跨域通信
网上搜到这个方法,但自己尝试的时候总会报错:
VM301:1 Uncaught DOMException: Failed to set the 'domain' property on 'Document': 'baidu.com' is not a suffix of 'corp.dinghuo123.com'.
at :1:17
因为同源安全政策不能直接修改。
首先补充一个知识点,然后再讲解怎么使用。
知识点:
一级域名 有的人叫根域名,如:dinghuo123.com、baidu.com、xx.com.cn、xx.cn.net 等等。
二级域名 是指增加了一级,包括www。如:www.dinghuo123.com、corp.dinghuo123.com、agent.dinghuo123.com 等等。所以有人把www.dinghuo123.com叫一级域名这是错误的。
document.domain 可以修改 corp.dinghuo123.com、agent.dinghuo123.com 为同一个主域 dinghuo123.com,此时即可通过上面步骤三-2实现父子之间的通信。
但是跨主域的时候就不能用这个方法了。
4.跨域(跨主域)
(1)方法
发送方:
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
//其他窗口的一个引用,
//(1)比如iframe的contentWindow属性、
//(2)执行window.open返回的窗口对象、
//(3)或者是命名过或数值索引的window.frames。
//(4)父级parent.window对象
message
//将要发送到其他 window的数据。它将会被结构化克隆算法序列化。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化。
//PS个人觉得若是对象尽量还是自行序列化吧避免出现什么奇怪的问题。
targetOrigin
//通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的orign属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
//PS简单来说就是*的话对方无论是什么URL都会触发onmessage回调,如果不是就会报错(图片见下方)
transfer //可选
//是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
//PS这个不是很懂,后面有时间研究。
targetOrigin报错图
postMessage兼容性
监听方:
window.onmessage = function(e){ console.log(e)}
e.source //可以获得父级window对象(必须是同域)
e.origin //检查postMessage的发送页面的源。
(2)实践
父向子
//父:
document.querySelector('#xx').onclick = function(){
window.frames[0].postMessage('testPost','*');
//document.querySelector('#Yiframe').contentWindow.postMessage('testPost','*'); 也可以
}
//子:
window.onmessage =function(e){
console.log('onmessage2',e,document.domain);
}
子向父
//子:
document.querySelector('#btn5').addEventListener('click',function(){
parent.window.postMessage('testChildPost','*');
});
//父:
window.onmessage = function(e){
console.log('onmessage父',e)
}
两个窗口:
理论上把window对象浏览器存储下再用上面的方式就能实现。未尝试。
(3)安全问题
如果您不希望从其他网站接收message,请不要为message事件添加任何事件侦听器。 这是一个完全万无一失的方式来避免安全问题。
如果您确实希望从其他网站接收message,请始终使用origin和source属性验证发件人的身份。 任何窗口(包括例如http://evil.example.com)都可以向任何其他窗口发送消息,并且您不能保证未知发件人不会发送恶意消息。 但是,验证身份后,您仍然应该始终验证接收到的消息的语法。 否则,您信任只发送受信任邮件的网站中的安全漏洞可能会在您的网站中打开跨网站脚本漏洞。
当您使用postMessage将数据发送到其他窗口时,始终指定精确的目标origin,而不是*。 恶意网站可以在您不知情的情况下更改窗口的位置,因此它可以拦截使用postMessage发送的数据。
四.路由变化以及前进后退。
控制台使用window.location.href会导致浏览器的url变化。
用户点击后退或者前进的时候,会根据之前的操作,完全依次复现(变化浏览器url和iframe内部页面路由变化)
window.history.go(xx) 和 window.history.back() ,无论在父页面还是在子页面中,使用的效果和浏览器的前进后退是一样的。
iframe中的页面使用window.location.href(和a标签)改变路由的时候不会引发浏览器url的变化,但会新增一条历史记录。
iframe每次重载,都会触发onload事件。
五.常见问题
iframe内的路由变化,iframe的src值不会变!!!
要获取iframe内的当前url,用document.querySelector('#Yiframe').contentWindow.location.href;
parent.window 在没有父级的时候 parent.window = window;
参考资料
SO JSON在线解析:http://www.sojson.com/blog/17...
浏览器同源政策: https://developer.mozilla.org...
postMessage:https://developer.mozilla.org...