iframe 動態onload事件處理方式

轉自:http://w3help.org/zh-cn/causes/SD9022html

 

標準參考

關於 HTML 4.01 規範中 BODY 標記的 onload 屬性說明: http://www.w3.org/TR/html401/struct/global.html#h-7.5.1瀏覽器

關於 HTML 4.01 規範中 onload 內在事件說明:http://www.w3.org/TR/html401/interact/scripts.html#adef-onloadapp

關於 DOM Level2 Events 規範中 load 事件說明:http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-htmlevents函數

問題描述

頁面加載完成後會觸發 onload 事件,一般下會使用 window.onload 、 document.body.onload、 HTMLIFrame.onload 方法來處理他;可是各瀏覽器對頁面 onload 事件處理方式並不一致,這些方法可能會致使頁面加載完成後沒法觸事件處理函數。spa

形成的影響

window.onload 與 document.body.onload 事件相互關係不明確。orm

IE6 IE7 IE8 中沒法經過爲屬性賦值方式爲 IFRAME 元素綁定 load 事件處理函數。htm

受影響的瀏覽器

IE6 IE7 IE8 Firefox  

問題分析

1、window.onload 與 document.body.onload 事件以及 BODY 標籤內的內聯 onload 事件,三者相互關係不明確

有關這兩個事件在 W3C 指定的規範中並無說明其區別,因爲 window 對象屬於 BOM 範疇沒有統一規範可依,各瀏覽器對其在此處的實現存有差別。對象

在微軟的 MSDN 中說明 document.body.onload 屬性是 window 的 onload 事件處理程序。其它瀏覽器廠商並無對此屬性作更細緻解釋。事件

分析如下代碼:ip

<button onclick="alert(document.body.onload);">查看本頁 document.body.onload 事件</button>
<button onclick="alert(window.onload);">查看本頁 window.onload 事件</button>
<button onclick="alert(window.onload===document.body.onload);">查看document.body.onload 事件與 window.onload 事件是否爲同一事件</button>
<br />
<script>
document.body.onload = function (){ // 函數 A
  document.getElementById("A").innerHTML = "document.body.onload 被觸發";
}
window.onload = function (){ // 函數 B document.getElementById("B").innerHTML = "window.onload 被觸發"; } </script> <span id="A" style="background:gold"></span> <span id="B" style="background:gray"></span> 

代碼中分別對兩種 onload 屬性賦值了不一樣的事件處理函數。其中 window.onload 先於 document.body.onload 被定義。若是他們二者使用的是同一事件處理源,則會發生 window 對象中 onload 事件定義被 body 的事件處理函數所覆蓋。

實際上個瀏覽器運行結果以下:

  IE6 IE7 IE8 Firefox Chrome Safari Opera
實際運行 window.onload 被觸發
document.body.onload 事件函數 函數 B 函數 A 函數 B
window.onload 事件函數 null 函數 B
二者事件處理函數是否一致 Flase Flase true

初步能夠看出:

  • 在 IE 中 window.onload 事件函數即便定義了,也會是 null ,它的事件處理函數始終是爲 document.body.onload 提供的;
  • 在 Firefox 中 document.body.onload 事件不與 window.onload 事件相同,後者事件函數不會覆蓋前者;
  • 在 Chrome Safari Opera 中 document.body.onload 事件處理函數被後聲明的 window.onload 事件處理函數覆蓋。

爲了更明確以上猜想,咱們將兩個事件處理函數位置對調後再來觀察實際效果:

window.onload = function () // 函數 B{
  document.getElementById("B").innerHTML = "window.onload 被觸發";
}

document.body.onload = function (){ // 函數 A document.getElementById("A").innerHTML = "document.body.onload 被觸發"; } 

此次試圖使用 document.body.onload 事件處理函數來覆蓋 window.onload,實際運行結果以下:

  IE6 IE7 IE8 Firefox Chrome Safari Opera
實際運行 document.body.onload 被觸發 window.onload .onload 被觸發 document.body.onload 被觸發
document.body.onload 事件函數 函數 A 函數 A 函數 A
window.onload 事件函數 null 函數 B
二者事件處理函數是否一致 Flase Flase true

能夠看出:

  • 不管如何在 IE 中 window.onload 事件函數即便定義了,也會是 null ,它的事件處理函數始終是爲 document.body.onload 提供的。
  • 在 Firefox 中 只有 window.onload 事件會觸發頁面加載完成事件,document.body.onload 只是個由用戶擴展的方法,並不觸發相應事件處理函數。這也說明了爲何僅在 Firefox 瀏覽器中,二者"事件"函數均被保留。
  • 在 Chrome Safari Opera 中頁面加載完成事件由 document.body.onload 和 window.onload 二者的事件處理函數定義順序有關,後定義的覆蓋以前定義的,二者最終會使用同一事件源函數處理事件內容。

在實際應用中 onload 事件還可能被寫在 BODY 標籤的屬性內,而不在腳本標籤中定義他的處理函數。此時代碼以下:

<script>
window.onload=function(){
  alert("window onload");
}
</script>
<body onload="alert('overridden window onload')">

此用例中首先在腳本標籤內爲 window.onload 事件附加了處理函數,而後有在 BODY 標籤內寫入 onload 事件處理代碼。若是 BODY 標籤內的 onload 事件處理與 window.onload 事件處理不一樣,就會彈出兩次對話框,而且能夠根據對話框出現的順序判斷哪一個 onload 事件處理在前。反之則只會彈出一個對話框,若是僅出現 "window onload" 字樣提示就說明 BODY 標籤內 onload 屬性無效,若是出現 「overridden window onload」 提示就說明 BODY 標籤內 onload 事件與 window.onload 事件爲同一事件處理機制,後者覆蓋了前者。

各瀏覽器運行結果以下:

  IE6 IE7 IE8 Firefox Chrome Safari Opera
實際運行 」overridden window onload「
二者均表明 window onload 事件 true

可見,在全部瀏覽器中均將,BODY 標籤內的內聯 onload 事件處理等同與 window.onload 事件處理。

結合上文說明可知, Firefox 中 BODY 標籤內的 onload 事件屬性與腳本標記內寫入的 document.body.onload 事件並不一致。

 

2、IE6 IE7 IE8 中沒法經過爲屬性賦值方式爲 IFRAME 元素綁定 load 事件處理函數

某些狀況下可能須要爲 IFRAME 標記動態添加 onload 監聽事件,其實現方法有一般有三種:

  1. 直接爲 HTMLIFrameElement.onload 屬性爲 IFRAME 標記賦值事件處理函數
  2. 使用 HTMLIFrameElement.setAttribute 方法爲 IFRAME 標記賦值事件處理函數
  3. 使用事件監聽方式爲 IFRAME 的 onload 事件綁定處理函數

根據 DOM 規範推薦使用第三種處理方式,可是因爲規範在不斷修正添加中,瀏覽器開發時可能相應的標準規範並未出現或者並不完善,這致使了各個版本瀏覽對此問題的實現差別。

如下將依次分析這三種方式在各瀏覽器內的處理狀況。

 

1.直接爲 HTMLIFrameElement.onload 屬性爲 IFRAME 標記賦值事件處理函數

分析如下代碼:

<body>
<div id="msgA">經過 HTMLIFrameElement.onload 屬性動態加入事件處理函數的 IFRAME 沒有觸發 onload 事件。</div>
<div id="msgB">靜態 IFRAME 沒有觸發 onload 事件。</div>
<br />
<script>

function iframeLoadA(){
  document.getElementById("msgA").innerHTML = "經過 HTMLIFrameElement.onload 屬性動態加入事件處理函數的 IFRAME 已經觸發 onload 事件。";
}
function iframeLoadB(){
  document.getElementById("msgB").innerHTML = "靜態 IFRAME 已經觸發 onload 事件。";
}

window.onload = function (){
  var iframeB = document.getElementById("ifarmeB");
  var iframeA = document.createElement('iframe');
  iframeA.onload = iframeLoadA;
  document.body.appendChild(iframeA);
}

</script>
<iframe id="ifarmeB" onload="iframeLoadB()"></iframe>
</body>

頁面中存在兩個 IFRAME 標記,ifrmaeA 標記爲動態生成,而且動態爲其 onload 屬性賦值了加載完成後的處理函數。而 iframeB 標記則是在頁面中靜態存在的,其 onload 屬性對應的事件處理函數已經被固定寫入。

運行此代碼,在各個瀏覽器中效果以下:

  IE6 IE7 IE8 Firefox Chrome Safari Opera
HTMLIFrameElement.onload = Function 沒有觸發 onload 事件 觸發 onload 事件
靜態 onload 屬性定義 觸發 onload 事件

可見,在 IE 瀏覽器中經過 HTMLIFrameElement.onload 屬性賦值方式沒法響應 IFRAME 標記的 onload 事件。而其餘瀏覽器均支持此寫法。

 

2.使用 HTMLIFrameElement.setAttribute 方法爲 IFRAME 標記賦值事件處理函數

將以上代碼稍做修改,將 HTMLIFrameElement.onload 賦值語句部分修改成 HTMLIFrameElement.setAttribute方法:

window.onload = function (){
  var iframeB = document.getElementById("ifarmeB");
  var iframeA = document.createElement('iframe');
  iframeA.setAttribute("onload","iframeLoadA()");
  document.body.appendChild(iframeA);
}

此時 ifrmaeA 標記的 onload 屬性以及事件處理函數被 DOM 標準方法 setAttribute 寫入。

運行此代碼,在各個瀏覽器中效果以下:

  IE6 IE7 IE8(Q) IE8(S) Firefox Chrome Safari Opera
HTMLIFrameElement.setAttribute 沒有觸發 onload 事件 觸發 onload 事件
靜態 onload 屬性定義 觸發 onload 事件

可見,在 IE 系列瀏覽器中僅有 IE8(S) 支持經過 setAttribute 方法爲 IFRAME 標記寫入 onload 屬性以及其事件處理函數。而其餘瀏覽器均支持此寫法。

 

3.使用事件監聽方式爲 IFRAME 的 onload 事件綁定處理函數

再將以上代碼稍做修改,使用 DOM 規範中推薦的事件監聽綁定方法爲 IFRAME 動態加入 onload 事件處理函數:

function addEvent(eventName,element,fn){
  if (element.attachEvent) element.attachEvent("on"+eventName,fn);
  else element.addEventListener(eventName,fn,false);
}
window.onload = function (){
  var iframeB = document.getElementById("ifarmeB");
  var iframeA = document.createElement('iframe');
  addEvent("load",iframeA,iframeLoadA);
  document.body.appendChild(iframeA);
}

代碼中爲了兼容 IE 私有的事件綁定方式,封裝了名爲 addEvent 的處理函數,他爲 IE 和其餘瀏覽器提供不一樣的事件綁定方法,以達到兼容效果。

運行此代碼,在各個瀏覽器中效果以下:

  IE6 IE7 IE8(Q) IE8(S) Firefox Chrome Safari Opera
onload 事件監聽綁定 觸發 onload 事件
靜態 onload 屬性定義

此時全部瀏覽器中爲 IFRAME 標記動態綁定的 onload 事件處理方法均生效。

 

綜合以上三種常見狀況能夠得出結論,除 IE 之外的瀏覽器均支持對以上三種動態定義 onload 事件處理函數的方法,而全部 IE 系列瀏覽器對 HTMLIFrameElement.onload 屬性的賦值不被支持,他們能夠經過 DOM 標準方法 setAttribute 來爲 HTMLIFrameElement 類型元素設置 onload 屬性,可是因爲 IE8 如下版本對 setAttribute 方法支持有限,致使僅 IE8(S) 下生效。最終 IE 瀏覽器只能經過事件監聽方式爲 HTMLIFrameElement 類型元素綁定 onload 事件處理函數。

 

解決方案

  1. 統一爲 window 對象的 onload 事件綁定函數,避免在 Firefox 中產生 document.body.onload 事件理解歧義。
  2. 統一使用 DOM 規範的事件監聽方法(或 IE 專有事件綁定方法)爲 IFRAME 標記綁定 onload 事件處理函數。
相關文章
相關標籤/搜索