iframe學習(三)之窗口監聽


前言

經常會遇到這樣一種情況。

在iframe里嵌入另外一個頁面時。如果iframe載入的頁面響應較快,或許我們感覺不到頁面載入的不同步,但試想,如果一個需要內嵌到iframe里的頁面的響應很慢,這里會出現一種什么現象呢?這時將會出現所有頁面已經載入完成,但

iframe元素處,將會出現空白,直到內嵌頁面完成載入時,該空白處才會顯示新載入的頁面。可想而知,一個頁面如果長時間的空白,對於瀏覽者來說將意味着什么。如果在內嵌頁面未載入完成時,給出一種加載提示信息。如:“頁面加載

中”之類的,我想這對瀏覽頁面用戶來講,將不再是煎熬,更是一種視覺上的享受。

為了實現這樣的效果,一般會采用如下原理處理。

  • iframe載入區域給出友好的提示信息。

  • 當iframe載入完成時,清空提示信息,而讓iframe顯示。

這些都比較容易,但現在的問題的關鍵是怎么監聽iframe元素內的頁面已經載入完成。

關鍵這個問題,一般來講,會分兩種情況來討論解決方案。

  • 同域嵌套:最好是讓子頁面調用父頁面的方法。

  • 異域嵌套:如果是異域,但子頁面無法修改,那么:在Firefox/Opera/Safari中,可以直接使用iframe onload事件;而在IE中,可以通過定時器測定子頁面的document.readyState,或者使用iframe onreadystatechange事件計算該事件的響應。

一個簡單的包含iframe的父頁面將是如下樣子的:

<!DOCTYPE ...>
<html xmlns="...">
  <head>
  <meta ... />
  <title>Iframe</title>
  <body>
    <iframe name="iframe1" id="iframe1" width="300" height="50" src="#" ></iframe>
    <script type="text/javascript">//codes here</script>
  </body>
</html>

開始:

一、同域嵌套

調用父頁面對象

parent.html function ifrmLoaded() { // code here
} sub.html window.onload = function() { window.parent.ifrmLoaded(); }

缺點:

  • 子父頁面必須在同域中

  • 需對子頁面有修改權;或者,可以請負責此子頁面的同事為我們添加一段代碼
<script type=”text/javascript”>
  if(window.parent!=window) window.parent.iframeCall(); </script>

把它放到window.onlad中,或者直接放在</body>之前。

注[1]:在對iframe或其它窗口性質的前端編程中,同域名是最完美的先天條件。只要在同一域名中,各個窗口間的對象是共享的,我們完全可以自由發揮,在不同的窗口間來回駕馭。總之,只有想不到,沒有做不到。

有時候,為了防止自己的頁面不被別人嵌套,可以采用如下方式解決:

if(window.parent!=window) window.parent.location="http://hqlong.com"; //or
if(window.top!=window) window.top.location="http://hqlong.com";

二、異域嵌套(或者子頁面已存在且無法修改)

在不同域名的頁面,瀏覽器出於安全考慮,幾乎完全封鎖了頁面間的對象來往

在異域的頁面嵌套中,子頁面總是可以直接改變父窗口的location以防止被嵌套,但父頁面對這個一點辦法也沒有。當然,子頁面除了僅僅永恆地擁有父窗口.location的修改權外,也沒有其它了。例如,在IE下,子頁面只能直接修改父頁面

的.location為另一個源:

<script tyle=”text/javascript”>parent.location=”http://anotherPage.com/”;</script>

但無法訪問其它對象,如window.name,document等,連location.href等location的子屬性就無法訪問。當然,在防止嵌套方面,使用top.location會更強大。

方法一:使用onreadystatechange來判斷

【Firefox/Opera/Safari中直接使用iframe onload事件】

document.getElementById('ifrm').onload = function() { //here doc
}

【在IE下,注冊iframe onreadystatechange事件】

iframe onreadystatechange事件

var oFrm = document.getElementById('ifrm'); oFrm.onreadystatechange = function() { if (this.readyState &amp;&amp; this.readyState == 'complete') { onComplete(); } }

定時器測document.readyState 

var oFrm = document.getElementById('ifrm'); var fmState=function(){ var state=null; if(document.readyState){ try{ state=oFrm.document.readyState; }catch(e){state=null;} if(state=="complete" || !state) { onComplete(); return; } window.setTimeout(fmState,10); } }; //在改變src或者通過form target提交表單時,執行語句:
if(fmState.TimeoutInt) window.clearTimeout(fmState.timeoutInt); fmState.timeoutInt = window.setTimeout(fmState,400);

每當iframe加載頁面,過程內會激活onreadystatechange事件三次,相應的狀態分別是loading,interactive和complete,而最后一次才是complete.

問題一:為什么要延時400毫秒?

因為javascript對DOM的操作是異步的,我們必須等待腳本對DOM落實執行后才開始下一步。400秒這個數取決 與客戶端的設備和瀏覽器的響應速度,好的設備的響應速度能在10毫秒以內甚至更快,但100毫秒左右可能比較大眾化,400毫秒應該是十分保守的了。總 之,較大的毫秒數能適合更多的用戶設備狀況,並能減少了客戶端設備的工作量。至於document.readyState,指的是iframe內子頁的docuent.readyState,而不是父頁面的

問題二:為什么使用try和 catch?

因為在異域的情況下,當iframe的子頁到達interactive狀態時,父頁面就會失去訪問權,所以最多只能返回到loaded這一步,因此IE出一個未知錯誤——其實就是沒有權限,所以try和catch,讓這個錯誤沉默下去。

兼容Firefox/Opera/Safari/IE的處理方式

var oFrm = document.getElementById('ifrm'); oFrm.onload = oFrm.onreadystatechange = function() { if (this.readyState && this.readyState != 'complete') return; else { onComplete(); } }

或者

var $iFrame=$("#IFrame"); $iFrame.prop("src","http://www.baidu.com"); if (!/*@aijquery@*/0) { //如果不是IE,IE的條件注釋  
    $iFrame[0].onload = function(){              alert("加載完畢");      };   }else{       $iFrame[0].onreadystatechange = function(){ // IE下的節點都有onreadystatechange這個事件  
         if (iframe.readyState == "complete"){               alert("加載完畢");          }       };   }

方法二:使用attachEvent判斷

var $iFrame=$("#IFrame"); $iFrame.prop("src","http://www.360.cn"); if ($iFrame[0].attachEvent){         $iFrame[0].attachEvent("onload", function(){ // IE  
              alert("加載完畢");        });   } else {         $iFrame[0].onload = function(){ // 非IE  
              alert("加載完畢");         };   }

方法三:使用jquery里的load來判斷

var $iFrame=$("#IFrame");      
$iFrame.prop("src","http://www.aijquery.cn");    
$iFrame.load(function(){       
    alert("加載完畢");    
});

注意

上面的方法必須是動態創建iframe或者動態添加iframe指定的src地址的情況下使用

參考

iframe載入完成時的事件監聽

jquery里判斷iFrame框架是否加載完成的三種方法

跨瀏覽器的iframe onload 事件監聽


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM