jQuery筆記-IFrame .load()事件
0 | 63,564 |
很久前討論過ready()與load()的差異,今天處理IFrame load()事件時,又有新發現。
依jQuery文件:
The
load
event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and thewindow
object.
需求是要在IFrame載入後由內嵌網頁中的元素取出資訊,透過.load()事件是最有效的切入點。但因為程式架構的關係,$("#myIFrame").load(function() { … });會在IFrame已載入後才執行,我發現在這種情境下,load事件將不會觸發。底下用程式來模擬:
先寫一個透過delay參數控制是否延遲兩秒才回傳的ASP.NET網頁(FramePage.aspx)以便控制內嵌網頁載入完成的時機:
<%@ Page Language="C#" %>
<!DOCTYPE html">
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(Request["delay"]))
{
System.Threading.Thread.Sleep(2000);
t.InnerHtml = "Delayed FramePage";
}
else t.InnerHtml = "FramePage";
}
</script>
<html>
<head runat="server">
<title></title>
</head>
<body>
<div id='t' runat="server"
style='width: 400px; height: 1200px; background-color: Silver;'>
</div>
</body>
</html>
接著,建立一個網頁放入兩個IFrame,src分別指向FramePage.aspx及FramePage.aspx?delay=Y(後者會延遲兩秒才載入完成)。網頁一開始就對兩個IFrame加掛load事件,透過setTimeout做法於1秒後再對兩個IFrame掛上第二組load事件。load事件中透過contents().find("#t")存取IFrame內的DOM元素(注意: 若IFrame內嵌網頁來自其他網站,則會因Same-Origin Policy限制無法存取,參考)
<!DOCTYPE html>
<html>
<head>
<title>Load Event Test</title>
<style>
.banner
{
padding: 5px; margin-bottom: 5px; width: 400px;
background-color: Brown; color: White;
}
</style>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.4.js">
</script>
<script>
$(function () {
var $log = $("#log");
function showMsg(m) {
$log.append("<li>" + m + "</li>");
}
var $frms = $("#frmA,#frmB");
$frms.load(function () {
showMsg("Load Event for " + this.id + "->" +
$(this).contents().find("div").text());
});
setTimeout(function () {
$frms.load(function () {
showMsg("Load Event(setTimeout) for " + this.id + "->" +
$(this).contents().find("div").text());
});
}, 1000);
});
</script>
</head>
<body>
<div class="banner">Banner</div>
<iframe id='frmA' src="FramePage.aspx" style='width: 200px; height: 100px;'
frameborder="0" border="0" cellspacing="0"></iframe>
<iframe id='frmB' src="FramePage.aspx?delay=Y" style='width: 200px; height: 100px;'
frameborder="0" border="0" cellspacing="0"></iframe>
<ul id="log"></ul>
</body>
</html>
執行結果如下,FramePage(frmA)是一開始就載入的,而Delayed FramePage(frmB)則要等2秒才會載入完成,發現透過setTimeout等1秒才設定的load事件,會因frmA已載入完成而未被觸發,2秒後才載入完成的frmB則二個事件都被觸發。(如下圖)
最後,我試著透過改掛ready事件,並加上setInterval檢查元件狀態的技巧解決問題。(另外,還發現在ready事件中,this不等於觸發事件的對象,需另外設法取得)
var $frms = $("#frmA,#frmB");
$frms.load(function () {
showMsg("Load Event for " + this.id + "->" +
$(this).contents().find("div").text());
});
setTimeout(function () {
$frms.each(function () {
//在ready事件中,this不會指向IFrame,故這裡另設變數保存之
var frm = this;
$(frm).ready(function () {
//ready事件不保證DOM已載入完成,故可能取不到資料
showMsg("Ready Event for " + frm.id + " -> " +
$(frm).contents().find("div").text());
//利用setInterval 0.1秒觸發一次檢查
var hnd = setInterval(function () {
var t = $(frm).contents().find("div").text();
//若已取到資料
if (t) {
//顯示結果
showMsg("Ready + setInterval Trick for " +
frm.id + " -> " + t);
//終止setInterval輪詢檢查
clearInterval(hnd);
}
}, 100);
});
});
}, 1000);
測試結果如下。ready事件一開始可取得已載入完成的frmA內容,但無法取得frmB的內容(因尚未載入),最後透過setInterval輪詢檢查技巧,總算能涵蓋frmA及frmB的情境。
Comments
Be the first to post a comment