也来谈谈"完美"跨域

关于跨域这个话题,很早就答应过要分享,但是因为懒,一直拖着,直到D2上有人谈起了“完美跨域”。“跨域”应该已经算不上什么难题了,只是提起 “完美”这两个字,突然觉得有了新意,那就写点什么吧,至少对自己有个交代嘛!跨域方案有很多,接下来一一枚举,会给出demo,demo的宗旨是尽可能 简单的让新手明白,各方案中跨域的原理,实际应用请酌情修改。

方案一、剪贴板

原理: IE本身依附于windows平台的特性为我们提供了一种基于iframe,利用内存来“绕行”的方案,在这里我称之为,本地存储原理。

缺点: 不支持非IE浏览器,并且影响到用户对剪贴板的操作,用户体验非常不好,特别是在IE7下,受安全等级影响,会弹出提示框。

演示: [ 点此阅览 ]

子页面在子域:demo.ioldfish.cn 下,在页面中加入如下代码获取页面高度并存入剪贴板。

< script type = "text/javascript" >
var ua = navigator. userAgent ;
if ( ( i = ua. indexOf ( "MSIE" ) ) >= 0 )
{
  var iObjH = window. document . documentElement . scrollHeight ;
 window. clipboardData . setData ( 'text' , String ( iObjH ) ) ;
}
</ script >

主页面在主域:www.ioldfish.cn 下,在页面中加入如下代码,获取剪贴板的值并赋值为子页面所在的iframe的高度。

< script type = "text/javascript" >
window. onload = function ( )
{
  var iObj = document. getElementById ( 'iId' ) ;
 iObj. style . height = parseInt ( window. clipboardData . getData ( 'text' ) ) + 'px' ;
}
</ script >

 

方案二、document.domain

原理: 设置了document.domain,欺骗浏览器

缺点: 无法实现不同主域之间的通讯。并且当在一个页面中还包含有其它的iframe时,会产生安全性异常,拒绝访问。

演示: [ 点此阅览 ]

主页面在主域:www.ioldfish.cn 下,子页面在子域:demo.ioldfish.cn 下,在两个页面的头部都加入如下代码:

< script type = "text/javascript" >
 document. domain = "ioldfish.cn" ;
</ script >
方案三、通过JS获取hash值实现通讯

原理: hash可以实现跨域传值实现跨域通讯。

缺点: 对于父窗口URL参数动态生成的,处理过程比较复杂一些。并且IE之外的浏览器遇到hash的改变会记录历史,影响浏览器的前进后退功能,体验不佳。

演示: [ 点此阅览 ]

子页面在主域:www.lzdaily.com 下,在页面中添加如下代码,因为hash是不受跨域限制的,所以可以将本页面的高度顺利的传送给主页面的hash。

< script type = "text/javascript" >
  var hashH = document. documentElement . scrollHeight ;
  var urlA = "http://www.ioldfish.cn/wp-content/demo/domain/hash/a2.html" ;
 parent. location . href = urlA + "#" + hashH ;
</ script >

主页面在主域:www.ioldfish.cn 下,在页面中添加如下代码,首先取得子页面传递过来的hash值,然后将hash值赋到子页面所在的iframe的高度上。

< script type = "text/javascript" >
window. onload = function ( )
{
  var iObj = document. getElementById ( 'iId' ) ;
  if ( location. hash )
  {
  iObj. style . height = location. hash . split ( "#" ) [ 1 ] + "px" ;
  }
}
</ script >
方案四、传hash值实现通讯改良版

原理: 该方案通过“前端代理”的方式,实现hash的传值,体验上比之方案三有了很大的提升。

缺点: 对于父窗口URL参数动态生成的,处理过程比较复杂一些。

演示: [ 点此阅览 ]

子页面在主域:www.lzdaily.com 下,在页面中添加如下代码,首先在页面里添加一个和主页面同域的iframe[也可动态生成],他的作用就像是个跳板。C页面中不需任何代码,只要确保有个页面就防止404错误就可以了!该方法通过修改iframe的name值同样可以跨域传值,只是比较”猥琐“而已。

<iframe id = "iframeC" name = "iframeC" src = "http://www.ioldfish.cn/wp-content/demo/domain/hashbetter/c.html" frameborder = "0" height = "0" ></ iframe >

然后在页面中加上如下代码,利用页面C的URL接收hash值,并负责把hash值传给同域下的主页面。

< script type = "text/javascript" >
 hashH = document. documentElement . scrollHeight ;
 urlC = "http://www.ioldfish.cn/wp-content/demo/domain/hashbetter/c.html" ;
 document. getElementById ( "iframeC" ) . src = urlC + "#" + hashH ;
</ script >

主页面在主域:www.ioldfish.cn 下,在页面中添加如下代码,获取从C页面中传递过来的hash值。这里应用到一个技巧,就是直接从A页面用frames["iId"].frames["iframeC"].location.hash ,可以直接访问并获取C页面的hash值。这样一来,通过代理页面传递hash值,比起方案三,大大提高了用户体验。

< script type = "text/javascript" >
window. onload = function ( )
{
  var iObj = document. getElementById ( 'iId' ) ;
 iObjH = frames [ "iId" ] . frames [ "iframeC" ] . location . hash ;
 iObj. style . height = iObjH. split ( "#" ) [ 1 ] + "px" ;
}
</ script >
方案五、JSONP

原理: 有点脚本注入的味道

缺点: 服务器端程序运行比脚本早,跨域交互时无法捕获前端页面元素的相关数据,比如自适应高度。

演示: [ 点此阅览 ]

主页面在主域:www.ioldfish.cn 下,在页面中添加如下代码,动态创建一个script,然后指定到子域的动态文件,在动态文件后面可以添加参数,在这里我加了一个回调函数,当请求返回后,会运行这个回调函数。

< script type = "text/javascript" >
function loadContent ( )
{
  var scriptDom = document. createElement ( 'script' ) ;
  var url = "http://www.lzdaily.com/domain/jsonp/Test.aspx?f=setDivContent'" ;
 scriptDom. src = url ;
 document. body . appendChild ( scriptDom ) ;
}
function setDivContent ( love )
{
  var fishDiv = document. getElementById ( "oldFish" ) ;
 fishDiv. innerHTML = love ;
}
</ script >

子页面在主域:www.lzdaily.com 下,在页面中添加如下代码,首先先取得主页面传过来的回调函数名,然后生成一段 javascript代码,以回调函数带参数的形式返回主页面,这样就完成了跨域之间的通讯。由于服务器端程序执行总是优先于javascript代码, 所以基本上没办法获取到子页面中DOM的相关数据,所以小白同学,我可以很负责人的告诉你,想通过这种方法实现跨域自适应高度是不可能的!

< script language = "C#" runat = "server" >
void Page_Load ( object sender , EventArgs e )
{
  string f = Request. QueryString [ "f" ] ;
  Response. Clear ( ) ;
  Response. ContentType = "application/x-javascript" ;
  Response. Write ( String. Format ( @ "{0}({1});" , f , 1122 ) ) ;
  Response. End ( ) ;
}
</ script >
方案六、window.name

原理: window.name本身并不能实现跨域,只是中间做了代理。

缺点: 获取异域的前端页面元素值有一定局限性,比如取自适应高度的值。但是此方法在前端页面元素的数据交互上明显比JSONP强。

演示: [ 点此阅览 ]

这个方案,YAHOO的同事已经给出了详细的demo,我就不重复了,演示demo出自YAHOO克军 之手。详细的说明可以参看“怿飞的BLOG” ,个人觉得方案四比window.name适用面更广一些。

方案七、window.navigator

原理: window.navigator这个对象是在所有的Iframe中均可以访问的对象。应该是IE的一个漏洞!

缺点: 不支持IE外的浏览器下的跨域。严格的dtd申明后,该方法失效!

演示: [ 点此阅览 ]

主页面在主域:www.ioldfish.cn 下,首先先申明一个Json用来保存所有页面的高度window.navigator.PagesHeight={“”:0}; ,然后根据name的属性找到页面的数据window.navigator.getData ,最后将页面的数据注册到window.navigator.PagesHeight 中。这里还定义了一个函数resetIframeData ,在页面加载的时候调用它,完成跨域的数据交互。注释中详细说明了参数的作用。

< script type = "text/javascript" >
window. navigator . PagesHeight = { "" : 0 } ;
window. navigator . getData = function ( pageName ) {
  return window. navigator . PagesHeight [ pageName ] ;
} ;
window. navigator . putData = function ( pageName , pageHeight )
{
 window. navigator . PagesHeight [ pageName ] = pageHeight ;
} ;
/*
 *iframeId:页面中iframe的标识id
 *key:子页面自定义的json标识,这里就是子页面定义的"PortalData".
 *defaultData:无法取到值时候调用
 */

function resetIframeData ( iframeId , key , defualtData )
{
  var obj = document. getElementById ( iframeId ) ;
  if ( window. navigator . getData )
  {
  var pageHeight = window. navigator . getData ( key ) ;
  if ( pageHeight && String ( pageHeight ) . match ( //d+/ ) )
  {
   obj. style . height = pageHeight + 'px' ;
  }
  else
  {
   obj. style . height = defualtData + 'px' ;
  }
  }
  else
  {
  obj. style . height = defualtData + 'px' ;
  }
}
</ script >

子页面在主域:www.lzdaily.com 下,获取到页面高度后,将高度存到主页定义的Json中,Json标识为”PortalData”,这里可以自定义。

< script type = "text/javascript" >
window. onload = function getPageData ( )
{
  var pageHeight = document. body . scrollHeight ;
  if ( window. navigator . putData )
  {
  window. navigator . putData ( "PortalData" , pageHeight ) ;
  }
}
</ script >

其实通过css也可以实现跨域,数据获取的实质其实就是动态载入一段CSS,然后解析其中的字段提取数据,这个方法比较“猥琐”,再这里就不多介绍了,当然flash也可以实现跨域,只是还没去实践,实践完了再补充。啥时候能补完呢?恩……

以上这么多方案,有可以“完美跨域”的吗?单一的看,我想没有吧,都有缺陷,但是只要不同情况下使用合适的方法,我想这才是最完美的!原来绕了一圈,我只是再说废话,哎!不论怎么样,还是希望这些废话对还在苦苦追求“完美”的同学们有所启发!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值