postMessage+window.name实现跨域iframe高度自适应兼容版

从前面的一篇文章中,我们知道HTML5 PostMessage不支持IE8以下的浏览器跨域,于是我想到了window.name支持ie6和ie7的方案,那么能否把这两种合并起来,给出一种全兼容的跨域方案呢?还别说,真有人能做到。来自:三水清

html5 postMessage实现跨域

postMessage是html5的一个新功能,可以实现不同域名之间的通信,通过给postMessage方式发送数据,监听则通过在父子窗口添加onmessage事件进行。
缺点也就很明显了,只有支持html5的浏览器才支持这种跨域方式,像IE6、7当然就拒之门外了!

window.name实现跨域

window.name实现跨域也是一个比较老的问题,之前kejun写过一个demo,可是给的却是同域名的通信。
其实kejun的实例中就是实现跨域的,不过他采用了同一个域名,而且过程比较崎岖:

  1. 建立iframe,指定src为被跨域的页面
  2. 被跨域文件修改window.name,将数据传给window.name
  3. iframe.src修改为本域代理文件,然后就可以取到contentWindow.name
  4. 进行处理数据,清除iframe
    充分的运用了window.name因为页面的url改变而name不改变的特性。
    但是如果我们是自己用,还是可以的,而如果我们放出去要别人使用我们写的东西,那样学习成本太大。

多浏览器双向跨域

为了解决上面的问题,我们使用的方法就是如果支持postMessage的浏览器就使用postMessage,如果不支持的就采用window.name的方式,幸运的是在IE6、7中支持跨域设置window.name,而我们就可以简单的通过window.name来跨域。然后建立计时器来监听window.name是否发生了变化,如果变化则接收并分析window.name,然后做请求。

演示和代码

<body>
	<div style="width:100%;border:1px solid green;">
		<h3>this page from :<span id="host"></span></h3>
		<input type="text" value="" id="data" /><button id="btn" onclick="send();">提交</button>
	</div>
	
	<iframe id="iframeA" src="http://1.qdemo.sinaapp.com/cross-domain/client.html" style="border:1px solid #ff6600;width:100%;height:300px;"></iframe>
	<script type="text/javascript">
		document.getElementById('host').innerHTML = location.host;
		function send(){
			var val = document.getElementById('data').value;
			sendMessage(val);
		}
		(function(win, doc){
			var ifr = doc.getElementById('iframeA').contentWindow;
			var cb = function(json){
				alert(location.host+" get msg:"+json);
			};
			var sendMessage = function(){
				if(win.postMessage){
					if (win.addEventListener) {
		                win.addEventListener("message",function(e){
						cb.call(win,e.data);
					},false);
		            }else if(win.attachEvent) {
		                win.attachEvent("onmessage",function(e){
						cb.call(win,e.data);
					});
		            }
					return function(data){
						ifr.postMessage(data,'*');
					};
				}else{
					var hash = '';
					
					setInterval(function(){
					
						if (win.name !== hash) {
							hash = win.name;
							cb.call(win, hash);
						}
					}, 50);
					return function(data){
						ifr.name = data;
					};
				}
			};
			win.sendMessage = sendMessage();
		})(window, document);
		
	
		
	</script>
</body>
<body>
	<h3>this page from :<span id="host"></span></h3>
	<input type="text" value="" id="data" /><button id="btn" onclick="send();">提交</button>
	<ul>
		<li>firefox、chrome等高级浏览器采用html5 postMessage方法</li>
		<li>IE6 7等使用window.name方法</li>
		<li>支持双向跨域,在chrome 13、firefox6、IE6+测试通过</li>
		<li>window.name可以通过data加随机数方式,避免两次提交的数据相同,本例没做处理,所以如果不改变value值点击提交是不会触发alert的</li>
		<li><a href="cross-domain.zip">demo下载</a></li>
	</ul>
	<script type="text/javascript">
		document.getElementById('host').innerHTML = location.host;
		function send(){
			var val = document.getElementById('data').value;
			sendMessage(val);
		}
		(function(win, doc){
			var ifr = win.parent;
			
			var cb = function(json){
				alert(location.host+"  get msg:"+json);
			};
			var sendMessage = function(){
				if(win.postMessage){
					if (win.addEventListener) {
		                win.addEventListener("message",function(e){
						cb.call(win,e.data);
					},false);
		            }else if(win.attachEvent) {
		                win.attachEvent("onmessage",function(e){
						cb.call(win,e.data);
					});
		            }

					return function(data){
						ifr.postMessage(data,'*');
					};
				}else{
					var hash = '';
					
					setInterval(function(){
						if(win.name!==hash){
							hash = win.name;
							cb.call(win,hash);
						}
					},50);
					return function(data){
						ifr.name = data;
					};
				}
			}
			win.sendMessage = sendMessage();
		})(window, document);
		
	</script>
</body>

基于上面的代码,结合我上篇文章的演示,我们再来给出一个iframe自适应高度的解决方案。

演示

原文:postMessage+window.name实现跨域iframe高度自适应兼容版 ,未经许可,禁止转载。
来源:前端开发博客 (http://caibaojian.com/postmessage-windowname.html)