第十五課:奇葩的元素節點iframe

 

iframe通常用來加載一個頁面,而後嵌入到主頁面中。建立起來消耗資源,並且消耗鏈接數。可是它是一個物超所值的東西,能夠實現無縫刷新,模擬onhashchange跨域,安全的加載第三方資源與廣告,實現富文本編輯,文件上傳,用它搞定IE6-IE7的select BUG(select標籤會移到遮罩層的上面來,可使用iframe遮住)。javascript

想要隱藏iframe那個很粗的邊框,咱們可使用frameBorder屬性。css

好比:<iframe frameborder=0  src=""  width=""  height=""></iframe>html

動態建立的iframe,標準瀏覽器可使用setAttribute來設置frameborder。但IE低版本只支持iframe.frameborder=0的用法(全部瀏覽器都支持)。java

去掉iframe中的滾動條:iframe.scrolling = "no"。node

IE下設置iframe的透明須要知足兩個條件:git

(1)iframe自身設置allowTransparency屬性爲true.(但設置了allowTransparency=true,就遮不住select了)github

(2)iframe中的文檔(src指向的頁面),background-color或body元素的bgColor屬性必須設置爲transparent。web

獲取iframe中的window對象ajax

在主頁面直接,frames[iframeName],iframes是主頁面中的一個對象,它的屬性iframeName能夠得到此名字的iframe的window對象。chrome

iframe.contentWindow,在主頁面經過document.getElementById("iframeID").contentWindow。

獲取iframe中的文檔對象

首先得到iframe的引用,好比:var node = document.getElementById("iframeID"),而後經過node.contentDocument || node.contentWindow.document。

前面是w3c,後面的寫法是IE.

斷定頁面是否在iframe裏面

在頁面中添加如下代碼:

window.onload = function(){  

  if(window != window.top) 在iframe中;

  if(window.frameElement !== null) 在iframe中;

  if(window.eval !== top.eval) 在iframe中;

}

斷定iframe是否加載完成

if(iframe.addEventListener){

  iframe.addEventListener("load",callback,false)

}

else{

  iframe.attachEvent("onload",callback);

}

不過動態建立的iframe,webkit系統瀏覽器可能會觸發兩次onload問題。

例如:

var iframe = document.createElement("iframe");

iframe.onload = function(){}

document.body.appendChild(iframe)

iframe.src="bokeyuan";

safari和chrome會在appendChild以後就進行第一次加載,而且在設置src以前就加載完成了,因此觸發了兩次。若是在插入body以前給iframe隨便設置一個src(除了空值),間接的加長第一次加載,那麼也只觸發一次。不設置或設置空值,它的src至關於連接到"about:blank"(空白頁)。

動態建立的iframe,若是須要用到name屬性,IE6-7下會有問題

if(不是IE6和IE7){

  iframe = document.createElement("iframe");

  iframe.name = name;

}else{

  iframe = document.createElement("<iframe name='" + name + "'>");

}

iframe和父窗口共享history,由於咱們可使用iframe解決ajax的後退按鈕問題

連接地址:https://github.com/devote/HTML5-History-API

清空iframe,同時不保留歷史的寫法

iframeWindow.location.replace("about:blank"),此replace方法不是字符串的replace方法,這個replace方法是location專有的方法,意思是替換window的連接地址,並且被替換的連接地址不存入歷史記錄中。

同源策略

同源策略:域名,協議,端口相同。

js容許同源訪問。

同一域名不一樣文件夾,同源。http://www.a.com/lab和http://www.a.com/lab1

域名和域名對應的ip,不一樣源。http://www.a.com和http://70.32.72.54

主域相同,子域不一樣,不一樣源。http://www.a.com和http://script.a.com

同一域名,不一樣二級域名,不一樣源。http://www.a.com和http://a.com,由於cookie,每次訪問相同的域名時,都會帶上cookie請求服務器。爲了請求同一域名下的文件帶上cookie,咱們能夠設置二級域名,這樣就不會帶上cookie了。好比:用戶操做的都是http://a.com域名下的頁面,每次請求都會帶上http://a.com域名的cookie,這時咱們設置boke.js爲http://www.a.com,這時請求boke.js時,就不會帶上http://a.com域名的cookie了。

斷定iframe與父頁面同源

在主頁面調用此方法,返回false就是不一樣源。

function isSameOrigin(iframe){

  var ret =false;

  try{

    ret = !!iframe.contentWindow.location.href;    

    //若是同源,就能夠訪問iframe的href。href若是存在,就會轉換成true。ret就返回true,about:blank跟任何域名同源。

  }catch(e){}    //若是不一樣源,訪問出錯,ret是默認的false

  return ret;

}

js跨域

跨大域:也就是主域名和子域名都不相同。

(1)postMesssage方法:在IE8以及以上瀏覽器支持,標準瀏覽器也支持。經過postMesssage方法傳數據,經過message事件取數據。(IE8,IE9只能傳字符串)

IE6和IE7能夠經過navigator對象搞定跨域。navigator對象是window對象的屬性。IE6和IE7下沒有控制檯,不能使用console對象的方法

  • appCodeName -- 瀏覽器代碼名的字符串表示
  • appName -- 官方瀏覽器名的字符串表示
  • appVersion -- 瀏覽器版本信息的字符串表示
  • cookieEnabled -- 若是啓用cookie返回true,不然返回false
  • javaEnabled -- 若是啓用java返回true,不然返回false
  • platform -- 瀏覽器所在計算機平臺的字符串表示
  • plugins -- 安裝在瀏覽器中的插件數組
  • taintEnabled -- 若是啓用了數據污點返回true,不然返回false
  • userAgent -- 用戶代理頭的字符串表示

主頁面:

iframe.attachEvent && iframe.attachEvent("onload",funtion(){   

  //iframe加載頁面完成,就會每隔3200毫秒,執行window.navigator.b方法(此方法是在iframe頁面中定義的,所以能夠傳入各類信息)

  setInterval(function(){  

      window.navigator.b(msg);   //主頁面把要傳的數據放進去。

  },3200);        

})

navigator.a = function(msg){

  msg;    (收到iframe頁面傳來的數據,能夠顯示出來,或者計算,或者傳給後臺)

}

iframe頁面:   

navigator.b = function(msg){

  msg;(收到主頁面傳來的數據,能夠顯示出來,或者計算,或者傳給後臺)

}

setInterval(function(){  

    window.navigator.a(msg1);   //iframe頁面把要傳的數據放進去。

},3300);     

(2)動態建立script,動態建立Image

(3)利用iframe和location.hash

a.com下的文件,cs1.html文件:     瀏覽器加載完頁面後,執行如下代碼,新建一個iframe,加載其餘域的頁面

function startRequest(){
    var ifr = document.createElement('iframe');
    ifr.style.display = 'none';
    ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';
    document.body.appendChild(ifr);
}
function checkHash() {
    try {
        var data = location.hash ? location.hash.substring(1) : '';
        if (console.log) {
            console.log('Now the data is '+data);
        }
    } catch(e) {};
}
startRequest();
setInterval(checkHash, 2000);   

cnblogs.com域名下的cs2.html:     //當iframe加載完以後,執行如下代碼

switch(location.hash){               //此hash值是從主頁面傳過來的,所以能夠算做主頁面傳過來的數據(a.com域傳給cnblogs.com域的數據)
    case '#paramdo':    
        callBack();
        break;
    case '#paramset':
        //do something……
        break;
}

function callBack(){
    try {
        parent.location.hash = 'somedata';     //由於不在同一個域,所不容許改變hash
    } catch (e) {
        // ie、chrome的安全機制沒法修改parent.location.hash, // 因此再建立一個iframe
        var ifrproxy = document.createElement('iframe');
        ifrproxy.style.display = 'none';
        ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意該文件在"a.com"域下 document.body.appendChild(ifrproxy); } }

a.com下的域名cs3.html:      //當iframe加載完以後,執行如下代碼

//由於parent.parent和自身屬於同一個域,因此能夠改變其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);      //此iframe(a.com)的parent是cs2(cnblogs.com),parent.parent是cs1(a.com)

只要這裏一改變主頁面的hash,主頁面就會把這個hash取到(這是cnblogs.com域傳給a.com域的數據)。

(4)利用iframe和window.name(這裏跨域的重點是主頁面能夠得到iframe的對象,而且能夠改變iframe的location。)

a.com/app.html:

var state = 0, 
    iframe = document.createElement('iframe'),
    loadfn = function() {
        if (state === 1) {
            var data = iframe.contentWindow.name;    // 由於此時,iframe中的頁面和主頁面不存在跨域,因此能夠經過iframe.contentWindow.name得到數據
            alert(data);    // 此數據,就是從b.com域名下傳來的數據。
        } else if (state === 0) {
            state = 1;
            iframe.src = "http://a.com/proxy.html";    // 這時改變iframe中的src,使之變成a.com域下的一個空html文件。
        }  
    };
    iframe.src = 'http://b.com/data.html';      //加載完這個頁面後,window.name 是b.com傳過來的數據,由於跨域,因此沒法取得iframe中的window.name
    if (iframe.attachEvent) {
        iframe.attachEvent('onload', loadfn);
    } else {
        iframe.onload  = loadfn;
    }
    document.body.appendChild(iframe);

b.com/data.html:

window.name = 'msg';      //域名b.com傳給域名a.com的數據  


跨小域:也就是主域名同樣,子域名不同

http://www.a.com/a.html和http://script.a.com/b.html兩個文件中分別加上document.domain = ‘a.com’;那麼他們就屬於同一域名下了,就能夠相互訪問了。

而後經過a.html文件中建立一個iframe,加載b.htm,最後就能夠在主頁面獲取iframe中b.htm頁面的document對象了。固然這種辦法只能解決主域相同而二級域名不一樣的狀況,若是你異想天開的把script.a.com的domian設爲alibaba.com那顯然是會報錯地!這種方式適用於{www.kuqin.com, kuqin.com, script.kuqin.com, css.kuqin.com}中的任何頁面相互通訊。

某一頁面的domain默認等於window.location.hostname。主域名是不帶www的域名,例如a.com,主域名前面帶的前綴一般都爲二級域名或多級域名,例如www.a.com實際上是二級域名。 domain只能設置爲主域名,不能夠在b.a.com中將domain設置爲c.a.com,只能設置爲它的主域名a.com。

 

 

 

加油!

相關文章
相關標籤/搜索