憨厚生

          ----Java's Slave----
          ***Java's Host***

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            165 隨筆 :: 17 文章 :: 90 評論 :: 0 Trackbacks
          轉 http://ued.alipay.com/?p=707

          關于跨域這個話題,很早就答應過要分享,但是因為懶,一直拖著,直到D2上有人談起了“完美跨域”。“跨域”應該已經算不上什么難題了,只是提起“完美”這兩個字,突然覺得有了新意,那就寫點什么吧,至少對自己有個交代嘛!跨域方案有很多,接下來一一枚舉,會給出demo,demo的宗旨是盡可能簡單的讓新手明白,各方案中跨域的原理,實際應用請酌情修改。

          方案一、剪貼板

          原理:IE本身依附于windows平臺的特性為我們提供了一種基于iframe,利用內存來“繞行”的方案,在這里我稱之為,本地存儲原理。

          缺點:不支持非IE瀏覽器,并且影響到用戶對剪貼板的操作,用戶體驗非常不好,特別是在IE7下,受安全等級影響,會彈出提示框。

          演示:[ 點此閱覽 ]

          子頁面在子域:demo.ioldfish.cn下,在頁面中加入如下代碼獲取頁面高度并存入剪貼板。

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

           

          主頁面在主域:www.ioldfish.cn下,在頁面中加入如下代碼,獲取剪貼板的值并賦值為子頁面所在的iframe的高度。

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

           

          方案二、document.domain

          原理:設置了document.domain,欺騙瀏覽器

          缺點:無法實現不同主域之間的通訊。并且當在一個頁面中還包含有其它的iframe時,會產生安全性異常,拒絕訪問。

          演示:[ 點此閱覽 ]

          主頁面在主域:www.ioldfish.cn下,子頁面在子域:demo.ioldfish.cn下,在兩個頁面的頭部都加入如下代碼:

          1. <script type="text/javascript">
          2.  document.domain="ioldfish.cn";
          3. </script>

           

          方案三、通過JS獲取hash值實現通訊

          原理:hash可以實現跨域傳值實現跨域通訊。

          缺點:對于父窗口URL參數動態生成的,處理過程比較復雜一些。并且IE之外的瀏覽器遇到hash的改變會記錄歷史,影響瀏覽器的前進后退功能,體驗不佳。

          演示:[ 點此閱覽 ]

          子頁面在主域:www.lzdaily.com下,在頁面中添加如下代碼,因為hash是不受跨域限制的,所以可以將本頁面的高度順利的傳送給主頁面的hash。

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

           

          主頁面在主域:www.ioldfish.cn下,在頁面中添加如下代碼,首先取得子頁面傳遞過來的hash值,然后將hash值賦到子頁面所在的iframe的高度上。

          1. <script type="text/javascript">
          2. window.onload = function()
          3. {
          4.  var iObj = document.getElementById('iId');
          5.  if(location.hash)
          6.  {
          7.   iObj.style.height=location.hash.split("#")[1]+"px";
          8.  }
          9. }
          10. </script>

           

          方案四、傳hash值實現通訊改良版

          原理:該方案通過“前端代理”的方式,實現hash的傳值,體驗上比之方案三有了很大的提升。

          缺點:對于父窗口URL參數動態生成的,處理過程比較復雜一些。

          演示:[ 點此閱覽 ]

          子頁面在主域:www.lzdaily.com下,在頁面中添加如下代碼,首先在頁面里添加一個和主頁面同域的iframe[也可動態生成],他的作用就像是個跳板。C頁面中不需任何代碼,只要確保有個頁面就防止404錯誤就可以了!該方法通過修改iframe的name值同樣可以跨域傳值,只是比較”猥瑣“而已。

          1. <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值傳給同域下的主頁面。

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

           

          主頁面在主域:www.ioldfish.cn下,在頁面中添加如下代碼,獲取從C頁面中傳遞過來的hash值。這里應用到一個技巧,就是直接從A頁面用frames["iId"].frames["iframeC"].location.hash,可以直接訪問并獲取C頁面的hash值。這樣一來,通過代理頁面傳遞hash值,比起方案三,大大提高了用戶體驗。

          1. <script type="text/javascript">
          2. window.onload = function()
          3. {
          4.  var iObj = document.getElementById('iId');
          5.  iObjH = frames["iId"].frames["iframeC"].location.hash;
          6.  iObj.style.height = iObjH.split("#")[1]+"px";
          7. }
          8. </script>

           

          方案五、JSONP

          原理:有點腳本注入的味道

          缺點:服務器端程序運行比腳本早,跨域交互時無法捕獲前端頁面元素的相關數據,比如自適應高度。

          演示:[ 點此閱覽 ]

          主頁面在主域:www.ioldfish.cn下,在頁面中添加如下代碼,動態創建一個script,然后指定到子域的動態文件,在動態文件后面可以添加參數,在這里我加了一個回調函數,當請求返回后,會運行這個回調函數。

          1. <script type="text/javascript">
          2. function loadContent()
          3. {
          4.  var scriptDom=document.createElement('script');
          5.  var url = "http://www.lzdaily.com/domain/jsonp/Test.aspx?f=setDivContent'";
          6.  scriptDom.src= url;
          7.  document.body.appendChild(scriptDom);
          8. } 
          9. function setDivContent(love)
          10. {
          11.  var fishDiv = document.getElementById("oldFish");
          12.  fishDiv.innerHTML = love;
          13. }
          14. </script>

           

          子頁面在主域:www.lzdaily.com下,在頁面中添加如下代碼,首先先取得主頁面傳過來的回調函數名,然后生成一段javascript代碼,以回調函數帶參數的形式返回主頁面,這樣就完成了跨域之間的通訊。由于服務器端程序執行總是優先于javascript代碼,所以基本上沒辦法獲取到子頁面中DOM的相關數據,所以小白同學,我可以很負責人的告訴你,想通過這種方法實現跨域自適應高度是不可能的!

          1. <script language="C#" runat="server">
          2. void Page_Load(object sender, EventArgs e)
          3. {
          4.   string f = Request.QueryString["f"];
          5.   Response.Clear();
          6.   Response.ContentType = "application/x-javascript";
          7.   Response.Write(String.Format(@"{0}({1});", f,1122));
          8.   Response.End();
          9. }
          10. </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,在頁面加載的時候調用它,完成跨域的數據交互。注釋中詳細說明了參數的作用。

          1. <script type="text/javascript">
          2. window.navigator.PagesHeight={"":0};   
          3. window.navigator.getData=function(pageName) {     
          4.  return window.navigator.PagesHeight[pageName];  
          5. };   
          6. window.navigator.putData=function(pageName,pageHeight) 
          7. {  
          8.  window.navigator.PagesHeight[pageName]=pageHeight;  
          9. };
          1. /*
          2. *iframeId:頁面中iframe的標識id
          3. *key:子頁面自定義的json標識,這里就是子頁面定義的"PortalData".
          4. *defaultData:無法取到值時候調用
          5. */
          6. function resetIframeData(iframeId,key,defualtData)
          7. {       
          8.  var obj=document.getElementById(iframeId);  
          9.  if(window.navigator.getData)
          10.  {  
          11.   var pageHeight = window.navigator.getData(key)
          12.   if(pageHeight && String(pageHeight).match(/\d+/))
          13.   {  
          14.    obj.style.height=pageHeight+'px';  
          15.   }
          16.   else
          17.   {  
          18.    obj.style.height=defualtData + 'px';  
          19.   }  
          20.  }
          21.  else
          22.  {  
          23.   obj.style.height=defualtData + 'px';  
          24.  }     
          25. } 
          26. </script>

           

          子頁面在主域:www.lzdaily.com下,獲取到頁面高度后,將高度存到主頁定義的Json中,Json標識為”PortalData”,這里可以自定義。

          1. <script type="text/javascript">
          2. window.onload = function getPageData()
          3. {         
          4.  var pageHeight = document.body.scrollHeight;  
          5.  if(window.navigator.putData)
          6.  {
          7.   window.navigator.putData("PortalData",pageHeight);
          8.  }
          9. } 
          10. </script>

           

          其實通過css也可以實現跨域,數據獲取的實質其實就是動態載入一段CSS,然后解析其中的字段提取數據,這個方法比較“猥瑣”,再這里就不多介紹了,當然flash也可以實現跨域,只是還沒去實踐,實踐完了再補充。啥時候能補完呢?恩……

          以上這么多方案,有可以“完美跨域”的嗎?單一的看,我想沒有吧,都有缺陷,但是只要不同情況下使用合適的方法,我想這才是最完美的!原來繞了一圈,我只是再說廢話,哎!不論怎么樣,還是希望這些廢話對還在苦苦追求“完美”的同學們有所啟發!

          posted on 2009-09-30 09:05 二胡 閱讀(303) 評論(0)  編輯  收藏 所屬分類: JS
          主站蜘蛛池模板: 潞西市| 河北省| 平武县| 苏尼特右旗| 定结县| 珲春市| 呼和浩特市| 尉犁县| 郎溪县| 鹤岗市| 兰溪市| 伊川县| 涪陵区| 隆昌县| 和政县| 贡山| 台中县| 荃湾区| 庆城县| 南川市| 湖口县| 太和县| 布尔津县| 息烽县| 南城县| 亚东县| 肇源县| 陆丰市| 武安市| 凤山县| 安国市| 新郑市| 杂多县| 东海县| 沅陵县| 曲麻莱县| 综艺| 兰西县| 西城区| 北京市| 伊通|