Iframe 有什麼好處,有什麼壞處?國內還有哪些知名網站仍用Iframe,為什麼?有哪些原來用的現在拋棄了?又是為什麼?
iframe原本的用法在現在看來是不合時宜的,問題太多了,不一一列舉,但是它的其他功能卻是不錯的黑魔法,這裡列舉一些,想到了再更新:
- 用來實現長連接,在websocket不可用的時候作為一種替代,最開始由google發明。Comet:基於 HTTP 長連接的「伺服器推」技術
- 跨域通信。JavaScript跨域總結與解決辦法 ,類似的還有瀏覽器多頁面通信,比如音樂播放器,用戶如果打開了多個tab頁,應該只有一個在播放。
- 歷史記錄管理,解決ajax化網站響應瀏覽器前進後退按鈕的方案,在html5的history api不可用時作為一種替代。
- 純前端的utf8和gbk編碼互轉。比如在utf8頁面需要生成一個gbk的encodeURIComponent字元串,可以通過頁面載入一個gbk的iframe,然後主頁面與子頁面通信的方式實現轉換,這樣就不用在頁面上插入一個非常巨大的編碼映射表文件了,其中子頁面內容:
&
&
&
&
&
&
&
把這個iframe部署到父頁面的同源服務上,就能在父頁面直接調用iframe中的encoding介面了。
- 評論里有提到,用iframe實現無刷新文件上傳,在FormData不可用時作為替代方案
- 在移動端用於從網頁調起客戶端應用(此方法在iphone上並不安全,慎用!具體風險看這裡 iOS URL Scheme 劫持 )。比如想在網頁中調起支付寶,我們可以創建一個iframe,src為:
alipayqr://platformapi/startapp?saId=10000007clientVersion=3.7.0.0718qrcode={支付二維碼掃描的url}
瀏覽器接收到這個url請求發現未知協議,會交給系統處理,系統就能調起支付寶客戶端了。我們還能趁機檢查一下用戶是否安裝客戶端:給iframe設置一個3-5秒的css3的transition過渡動畫,然後監聽動畫完成事件,如果用戶安裝了客戶端,那麼系統會調起,並將瀏覽器轉入後台運行,進入後台的瀏覽器一般不會再執行css動畫,這樣,我們就能通過判斷css動畫執行的時長是否超過預設來判斷用戶是否安裝某個客戶端了:
/**
* 調起客戶端
* @param url {String}
* @param onSuccess {Function}
* @param onFail {Function}
*/
module.exports = function(url, onSuccess, onFail){
// 記錄起始時間
var last = Date.now();// 創建一個iframe
var ifr = document.createElement("IFRAME");
ifr.src = url;
// 飄出屏幕外
ifr.style.position = "absolute";
ifr.style.left = "-1000px";
ifr.style.top = "-1000px";
ifr.style.width = "1px";
ifr.style.height = "1px";
// 設置一個4秒的動畫用於檢查客戶端是否被調起
ifr.style.webkitTransition = "all 4s";
document.body.appendChild(ifr);
setTimeout(function(){
// 監聽動畫完成時間
ifr.addEventListener("webkitTransitionEnd", function(){
document.body.removeChild(ifr);
if(Date.now() - last &< 6000){ // 如果動畫執行時間在預設範圍內,就認為沒有調起客戶端 if(typeof onFail === "function"){ onFail(); } } else if(typeof onSuccess === "function") { // 動畫執行超過預設範圍,認為調起成功 onSuccess(); } }, false); // 啟動動畫 ifr.style.left = "-10px"; }, 0); }; - 創建一個全新的獨立的宿主環境。經 @EtherDream 大神提醒,iframe還可以用於創建新的宿主環境,用於隔離或者訪問原始介面及對象,比如有些前端安全的防範會覆蓋一些原生的方法防止惡意調用,那我們就能通過創建一個iframe,然後從iframe中取回原始對象和方法來破解這種防範。類似的還有 @賀師俊 曾經提到的javascript裸對象創建中的一種方法:如何創建一個JavaScript裸對象 ,一般所見即所得編輯器也是由iframe創建的, @Dion 的回答有提到
- IE6下用於遮罩select。經 @yaniv 提醒想起來的。曾經在ie6時代,想搞一個模態窗口,如果窗口疊加在select元素上面,是遮不住select的,為了解決這個問題,可以通過在模態窗口元素下面墊一個iframe來實現遮罩,好坑爹的ie6,還我青春韶華~~
- to be continued ...
- 使用 iframe 是不是一個好的用法(good practice),不能一概而論,但是可以肯定是,現在的大部分網站避免採用這種方式的。
- 比較早期的網站使用 iframe,主要是用於導航欄(navigator)。為什麼?因為一個網站很多頁面的導航欄部分是相同的,在避免切換頁面的時候重複下載,將導航欄和正文分開在 iframe 中,是一個方便的做法。同時帶來的不利是,默認情況下,使用了 iframe 的網站的 URL 不會隨著頁面的變化而變化。這就意味著一旦刷新,網站可能又回到首頁。那麼現在的網站是如何解決不同頁面使用相同的 navigator 而避免重複編碼呢?不同後台技術都有自己的方法,比如 ASP 有 SSI,PHP 有 require、require_once 或 include 函數,JSP 也有 include 指令。
- iframe 一直是瀏覽器標準規範之一,只有很早期的瀏覽器不支持 iframe,現在幾乎已絕跡。所以從兼容性上來說,iframe 是沒問題的。
- 那麼現在什麼時候會用到 iframe 呢?因為 iframe 的頁面和父頁面(parent)是分開的,所以它意味著,這是一個獨立的區域,不受 parent 的 CSS 或者全局的 JavaScript 的影響。
典型的,比如所見即所得的網頁編輯器(WYSIWYG Online HTML Editor),因為它們需要 reset 自己的 CSS 到自己的標準,而不被 parent CSS 的 override。
- 說到上面一點了,順便說一下,知乎的這個編輯器不是用 iframe,它使用了一種叫 contentEditable 的屬性,用來啟用頁面元素的編輯,在早期版本 IE 下不支持的。
- 正是因為剛剛提到的 iframe 等於新建了一個全新的,不受 parent 影響的頁面上下文,所以在一定程度上,類似於沙箱隔離(sandbox)。除此之外,如果有可以不用 iframe 來解決的問題,還是避免使用 iframe。替代方案一般就是動態語言的 include 機制、ajax 動態填充內容,以及以後會普及的 contentEditable。
HTML規範說:The iframe element represents a nested browsing
context.
歷史上,iframe 常被用於復用部分界面,但是多數情況下並不合適。
現在,應該使用 iframe 的例子如:
1. 沙箱隔離。2. 引用第三方內容。3. 獨立的帶有交互的內容,比如幻燈片。4. 需要保持獨立焦點和歷史管理的子窗口,如複雜的Web應用。
註:登錄彈窗用 iframe 未必合適。HTML標準新增了dialog元素,可能更適合。我也說一個吧,在手機web裡面,如果要載入大量圖片(例如一些瀑布了形式的圖片網站,或社交網站),一旦圖片載入過多,內存佔用大,頁面會stuck,如果使用iframe來載入一批圖片,當這批圖片滿足某個條件(例如遠離屏幕的可視區域),直接把iframe幹掉,清除內存佔用,乾淨利落~~
我再補充一個使用&