iframe 很多網站都在用,雖然方便開發與維護(可能同時有幾個頁面調用同一個 iframe ),不過卻存在安全問題。嵌入 iframe 的頁面,父頁面與子頁面均可以很輕鬆的在同域或跨子域的情況下進行讀寫操作;在完全不同域的情況下,也可以通過更改 hash 的方式進行通訊。下面我在九個不同(版本的)瀏覽器中對此進行資料轉送與更改的相容性測試。
同域或跨子域讀寫操作 iframe 裡的內容
父頁面讀寫操作子頁面:
代碼如下 |
複製代碼 |
<iframe id="test-iframe" name="test-iframe" src="child.html" scrolling="no" frameborder="0"></iframe> <script> window.onload = function () { /* * 下面兩種擷取節點內容的方式都可以。 * 由於 IE6, IE7 不支援 contentDocument 屬性,所以此處用了通用的 * window.frames["iframe Name"] or window.frames[index] */ var d = window.frames["test-iframe"].document; d.getElementsByTagName('h1')[0].innerHTML = 'pp'; alert(d.getElementsByTagName('h1')[0].firstChild.data); } </script> |
註:在請務必通過 window.onload 方法訪問 iframe 中的節點,否則瀏覽器會提示錯誤-拒絕訪問。在 IE8, Firefox3.6, Opera11 下在 DOMReady 時也可以訪問 iframe 中的節點。
子頁面讀寫操作父頁面:
代碼如下 |
複製代碼 |
<script> parent.document.getElementsByTagName('h1')[0].innerHTML = 'pp'; alert(parent.document.getElementsByTagName('h1')[0].firstChild.data); </script> |
小結:
•1 測試通過 IE6, IE7, IE8, Firefox2.0, Firefox3.0, Firefox3.6, Chrome8, Opera11, Safari5.
•2 查閱資料得出 document.getElementById(‘id name’).contentDocument 全等於 window.frames["iframe Name"].document.
•3 跨子域時,需要在父頁面和子頁面 JS 中分別加上 document.domain = 'xxx.com';
跨網域作業 iframe 裡內容
當兩個網頁所在域不同時,要實現資料的互相調用,只能通過 JS 改變 location 對象的 hash 屬性的值來做到互相通訊。
父頁面:
代碼如下 |
複製代碼 |
<iframe id="test-iframe" src="http://www.yyy.com/child.html" scrolling="no" frameborder="0"></iframe> <input type="button" value="send" onclick="sendRequest()" /> <script> function sendRequest() { document.getElementById('test-iframe').src += '#a'; } var interval = window.setInterval(function(){ if(location.hash) { alert(location.hash); window.clearInterval(interval); } },1000); </script> |
子頁面:
代碼如下 |
複製代碼 |
<h1>RRRRRR</h1> <script> var url = 'http://www.xxx.com/father.html'; oldHash = self.location.hash, newHash, interval = window.setInterval(function(){ newHash = self.location.hash; if(oldHash != self.location.hash) { document.getElementsByTagName('h1')[0].innerHTML = 'pp'; //alert(parent.location.href); //去掉這個注釋,瀏覽器會提示無許可權 parent.location.href = url + '#b'; window.clearInterval(interval); } },500); </script> |
小結:
•1 經測試 IE6, IE7, IE8, Firefox2.0, Firefox3.0, Firefox3.6, Chrome8, Opera11, Safari5, 除 IE6, IE7 外只要改變 hash 就會記錄在瀏覽器 history 中。
•2 我有試圖在子頁面用 parent.location.replace 的方法來避免父頁面向伺服器發送請求而進行跳轉,這樣理論上瀏覽器就不會記錄曆史,但未能奏效。
•2 子頁面無權讀取父頁面的 url, 但可以對父頁面的 url 進行寫操作,所以跨網域作業時,要提前得知父頁面的url
iframe自適應,跨域,JS的document.domain
判斷子頁面的域是否與父頁面的域相同:
代碼如下 |
複製代碼 |
document.domain == parent.document.domain |
關於iframe的自適應,跨域可以參考下面步驟:
1.在父視窗加上document.domain(也就是調用IFRAME的那個視窗)
1 //如“www.a.com”中的"a.com"
代碼如下 |
複製代碼 |
document.domain = "a.com";
|
2.在子視窗加上下邊代碼(也就是IFRAME本身裡邊)
代碼如下 |
複製代碼 |
function iframeAutoFit() { try { if(window!=parent) { var a = parent.document.getElementsByTagName("iframe"); for(var i=0; i<a.length; i++) { if(a[i].contentWindow==window) { var h1=0, h2=0, d=document, ddd=d.documentElement; a[i].parentNode.style.height = a[i].offsetHeight +"px"; a[i].style.height = "10px"; if(dd && dd.scrollHeight) h1=dd.scrollHeight; if(d.body) h2=d.body.scrollHeight; var h=Math.max(h1, h2); if(document.all){h += 4;} if(window.opera){h += 1;} a[i].style.height = a[i].parentNode.style.height = h +"px"; } } } } catch (ex){} } if(window.attachEvent) { window.attachEvent("onload", iframeAutoFit); }else if(window.addEventListener) { window.addEventListener('load', iframeAutoFit, false); } |
3.細節問題 IFRAME外邊加個DIV,否則Firefox下有問題,寬度設定好 否則它們都有問題
代碼如下 |
複製代碼 |
<div style="width:100%;margin:0 0 10px 0;"> <iframe align='middle' src='http://comments.cnmo.com/iframe_comment.php?kindid=9&articleid=<?=$pic_id?>&tw=620&style=11&font_num=180&pagesize=3' frameborder='0' marginwidth='0' marginheight='0' width='100%' scrolling='no' height='450px' style='margin-top:15px;'></iframe> </div> |
OK 了。
frame/iframe 架構的網站中js彈出浮層記錄
核心:取得DOM最底層的對象,然後再往下去對象[想要彈出浮層的那個frame/iframe],再往後的操作就跟非架構的一樣了。
HTML代碼:
代碼如下 |
複製代碼 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>frame/iframe架構中js彈出浮層</title> </head> <body> <frameset rows="64,*,64" frameborder="no" border="0" framespacing="0"> <noframes> <body>你的瀏覽器不支援架構,所以無法使用本系統,建議你升級瀏覽器版本或者使用其它瀏覽器。</body> </noframes> <frame src="header.html" name="headerFrame" noresize="noresize" frameborder="no" scrolling="no" marginwidth="0" marginheight="0" target="main" /> <frameset cols="200,*" id="frame"> <frame src="left.html" name="leftFrame" noresize="noresize" marginwidth="0" marginheight="0" frameborder="0" scrolling="no" target="main" /> <frame src="right.html" name="main" marginwidth="0" marginheight="0" frameborder="0" scrolling="auto" target="_self" /> </frameset> <frame src="footer.html" name="footerFrame" noresize="noresize" frameborder="no" scrolling="no" marginwidth="0" marginheight="0" target="main" /> </frameset> </body> </html> |
如上邊的頁面配置,我們要在id為main的frame裡彈出一個浮層以展示相關資訊。
彈出浮層JS代碼:
代碼如下 |
複製代碼 |
function popShow() { var mainFrame = window.top.main.document; var bkg = mainFrame.getElementById("pop_bkg"); // 取得浮層那個透明背景對象 if(bkg==null) { //不存在則建立 bkg = mainFrame.createElement("div"); bkg.className = "pop_bkg"; bkg.id = "pop_bkg"; mainFrame.body.appendChild(bkg); } var pop_div = mainFrame.getElementById("pop_addr_div"); // 取得顯示資訊的那個Div對象 if(pop_div == null){//不存在則建立 pop_div = mainFrame.createElement("pop_addr_div"); pop_div.id = "pop_addr_div"; mainFrame.body.appendChild(pop_div); } bkg.style.display = "block"; pop_div.style.display = "block"; } |
這樣就可以正常的彈出個浮層了。