by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=1294
一、前言碎碎念
我從來對iframe就沒有什么好感,對其基本上是不屑一顧。但是人在江湖,身不由己。經理發話,新功能使用iframe實現,沒辦法,只好折騰,兩大煩人的東西,一是帶遮罩的彈框提示,而是iframe高度問題。前一個煩人的問題使用其他形式的提示來規避,后一人擾人的問題確實沒有什么經驗,花了點時間折騰了下,基本上實現了效果,跨域沒問題,兼容性也沒問題,於是,寫個小文備忘下,下次再使用的時候就到這兒拷貝核心代碼。
口碑UED有篇大米的“再談iframe自適應高度”一文,可以看看,雖然貌似兼容性沒有個調調。此文評論有個如下的鏈接地址:http://css-tricks.com/examples/iFrameResize/crossdomain.php,跨域且比較兼容的iframe高度定時自動變化的demo,但是,此demo中的js像個老太太一樣啰哩吧嗦,裹腳布般又臭又長,於是,對js腳本重新修身整形,把老太太變成了苗條妙齡少女。
二、原理簡述
本文展示的實現方法需要父頁面和框架子頁面相互配合。框架頁面的任務就是向父頁面傳遞其高度值,父頁面的任務就是獲取這個高度,然后改變iframe的高度。這個道理不難理解,兒子想買雙增高鞋,但是由於沒有經濟實力買不起,於是就告訴他的老爸:“老爸,我要買雙40碼的增高20厘米的增高鞋”,老爸收到了這個信息,就可以掏鈔票給兒子買鞋讓兒子增高。
關鍵是這個訊息如何傳遞。因為這個老爸是后爸(跨域),兒子心理上有障礙,說不出口。這時候,就需要媒介來幫忙傳遞訊息,例如兒子的偶噶桑(お母さん)。那么,在本文中,這個協助傳遞高度信息的媒介是什么呢?答案就是地址欄的錨點。如下圖:
將高度以如下錨點形式傳遞:
#height=372
iframe頁面內部通過window.top.location屬性修改父頁面的地址欄地址,從而將帶有高度值的地址傳遞過去。地址欄地址在只增加錨點的情況下是不會刷新頁面的、或是產生跳轉什么的。
在父頁面,需要設定一個定時器,例如每200毫秒去獲取iframe的高度,如果高度改變,則取修改iframe的高度。您可以會對此做法的效率有所疑問,根據大米的測試,同時開5個窗口(IE6、IE7、FF、Opera、Safari)執行這個代碼,不會對CPU有什么影響,甚至調整到2ms,也沒影響(基本維持在0%占用率)。所以,對於效率基本上不用擔心。
三、iframe頁面跳轉和無跳轉實例
通過window.top.location修改父頁面的地址欄地址,而不刷新頁面,顯然是需要得知父頁面的頁面絕路地址的。同樣可以通過window.top.location獲取,一了百了。
於是,父子在地址欄和錨點媒介幫助下打情罵俏,產生交流與互動,實現高度自適應的交互。
以下就是實例了。
您可以狠狠地點擊這里:iframe高度動態自適應demo(無跳轉)
你可以繼續狠狠地點擊這里:iframe高度動態自適應demo(跳轉)
這兩個實例父頁面的js代碼和iframe頁面中的都是一樣的,所以,統一展示,如下:
首先是子頁面,子頁面的任務就是傳遞高度而已,假設現在已經得到iframe當前的頁面高度是1294(單位像素,省略)。則核心部分的js代碼就是:
//此處window.top.location獲取主頁面地址的方法有跨域權限的問題,替代方法參見下面的補充。
//或者這里直接使用死地址,即hostUrl = "http://www.host.com/",這是沒有任何跨域的問題的。
var hostUrl = window.top.location.toString().split("#")[0];
if (hostUrl) {
hostUrl += "#height=" + 1294;
window.top.location = hostUrl;
}
補充於2010-12-08
根據evonli的建議與提醒,iframe頁面的高度傳遞不需要上面這么多代碼,直接改變hash就可以了,如下:
window.top.location.hash = "#height=" + 1294;
但是,在IE瀏覽器下(以及Chrome下),貌似此方法,不支持跨域的情況(會報權限錯誤)。看來可能還是得使用iframe的src傳遞父頁面地址,后者是通過cookie,或者其他形式,或是是寫死的頁面地址等形式。
目前看來,貌似只有(window.top.location = 父頁面地址 + 錨點)無兼容性問題,且支持跨域。所以,我開始理解為何crossdomain.php父頁面的地址要通過iframe的src地址傳遞的了。但是,此方法似乎只適用於iframe頁面無跳轉的情況。因為發生跳轉后,iframe地址就變了。
通過iframe傳遞父頁面地址方法類似下面的代碼,其中iframe指iframe的DOM對象。
var href = window.location.href, index = href.indexOf("#"); if (index !== -1) { href = href.slice(0, index); } iframe.src = iframe.src + "#" + href;
iframe子頁面可以通過:
window.location.hash.slice(1);
獲得父頁面的地址欄的絕對地址。然后,就是改變父頁面的地址:
var hostUrl = window.location.hash.slice(1); hostUrl += "#height=" + 1294; window.top.location = hostUrl;
//zxx:補充內容結束
下面是改變iframe的高度值, 理論上,則iframe以通過錨點附了高度值的url地址應該類似下面,http://www.google.com#height=1294,於是工作很簡單,就是得到這個1294就可以了,於是有類似下面的代碼:
var iframeHeight = function() { var hash = window.location.hash.slice(1); if (hash && /height=/.test(hash)) { iframe.height = hash.replace("height=", ""); } setTimeout(iframeHeight, 200); }; iframeHeight();
最后就有類似下面的效果,默認iframe高度120:
點擊iframe頁面中的“顯示圖片”按鈕后,很快的,iframe高度自動跟隨增加,如下圖所示:
四、開心網的做法
開心網第三方開發的組件也是以iframe框架的形式嵌入的。其高度自適應實現原理大致如下。
內嵌的iframe動態生成一個以開心網提供的頁面地址的高寬為0且隱藏的iframe,此iframe頁面地址與開心網主頁面是同域的,於是,其中iframe頁面內部的腳本就可以對主頁面進行操作了(動態改變第三方iframe的高度)。
var t = document.createElement("div"); t.innerHTML = '<iframe style="display:none;" src="http://www.kaixin001.com/interface/domain_proxy.php? para=1294&type=3'" scrolling="no" height="0" width="0"></iframe>'; document.body.appendChild(t.firstChild);
五、結語
本着簡單示范的目的,文中展示的代碼算是相對比較簡潔的。但是,實際使用的時候,要考慮一些細節,或是性能上的調整。例如,緩存當前高度,只有高度改變才去修改iframe的高度(這個實例中並沒有體現)。
總的來說應該是相當易懂的。window.top.location為中介,iframe把高度亦錨點的形式告知父頁面,父頁面通過此高度修改iframe的高度值。寥寥十幾行js代碼,沒有什么復雜邏輯和處理,一些簡單的字符串處理。
最后,對iframe基本上沒有什么研究,所以文中可能有表述不准確的地方,或是實現方法上有潛在問題,歡迎大家指正,不甚感謝。就這些。
原創文章,轉載請注明來自張鑫旭-鑫空間-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=1294