Javascript架構(iframe)之間相互傳值程式碼

來源:互聯網
上載者:User

很多架構存在父子關係,操作起來十分麻煩,很多同學經常出現這樣悲催的代碼:

 代碼如下 複製代碼

window.parent.document.getElementById("main")
.contentWindow.document.getElementById('input').value =
document.getElementById('myIframe')
.contentWindow.document.getElementById('s0').value;


看一個我自己做的執行個體


iframe的調用包括以下幾個方面:(調用包含html dom,js全域變數,js方法)

首頁面調用iframe;

iframe頁面調用首頁面;

首頁面的包含的iframe之間相互調用;

 

主要知識點


1:document.getElementById("ii").contentWindow 得到iframe對象後,就可以通過contentWindow得到iframe包含頁面的window對象,然後就可以正常訪問頁面元素了;


2:$("#ii")[0].contentWindow  如果用jquery選取器獲得iframe,需要加一個【0】;


3:$("#ii")[0].contentWindow.$("#dd").val() 可以在得到iframe的window對象後接著使用jquery選取器進行頁面操作;


4:$("#ii")[0].contentWindow.hellobaby="dsafdsafsdafsdafsdafsdafsadfsadfsdafsadfdsaffdsaaaaaaaaaaaaa"; 可以通過這種方式向iframe頁面傳遞參數,在iframe頁面window.hellobaby就可以擷取到值,hellobaby是自訂的變數;


5:在iframe頁面通過parent可以獲得首頁面的window,接著就可以正常訪問父親頁面的元素了;


6:parent.$("#ii")[0].contentWindow.ff; 同級iframe頁面之間調用,需要先得到父親的window,然後調用同級的iframe得到window進行操作;

 

源碼


main.html

 代碼如下 複製代碼

?<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>顯示圖表</title>
<script src="/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
    var gg="dsafdsafdsafdsafsdaf";
    function ggMM() {
        alert("2222222222222222222222222222222");
    }
    function callIframeMethod() {
        //document.getElementById("ii").contentWindow.test();
        $("#ii")[0].contentWindow.test(); //用jquery調用需要加一個[0]
    }
    function callIframeField() {
        alert($("#ii")[0].contentWindow.ff);
    }
    function callIframeHtml() {
        alert($("#ii")[0].contentWindow.$("#dd").val());
        //alert($("#ii")[0].contentWindow.document.getElementById("dd").value);
        //alert($("#ii")[0].contentWindow.document.getElementById("dd").value);             
    }   
    function giveParameter() {
        $("#ii")[0].contentWindow.hellobaby="dsafdsafsdafsdafsdafsdafsadfsadfsdafsadfdsaffdsaaaaaaaaaaaaa";
    }
</script>
</head>
<body>
    <a href="#" onClick="giveParameter();">參數傳遞</a>
    <a href="#" onClick="callIframeMethod();">調用子iframe方法</a>
    <a href="#" onClick="callIframeField();">調用子iframe變數</a>
    <a href="#" onClick="callIframeHtml();">調用子iframe組件</a></br>  
    <iframe id="ii" src="frame.htm" width="100%" frameborder="0"></iframe>
    <iframe id="new" src="newFrame.htm" width="100%" frameborder="0"></iframe>
</body>
</html>

frame.htm

 代碼如下 複製代碼
?<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>顯示圖表</title>
<script src="scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
 
var ff="adfdasfdsafdsafdsaf";
function test() {
    alert($("#dd").val());
}
function callMainField() {
    alert(parent.gg);
}
function callMainMethod() {
    parent.ggMM();
}
function callMainHtml() {
    alert(parent.$("#ii").attr("id"));
}
function getParameter() {
    alert(window.hellobaby);
}
</script>
</head>
<body>
    <a href="#" onClick="getParameter();">接受參數</a>
    <a href="#" onClick="callMainMethod();">調用子iframe方法</a>
    <a href="#" onClick="callMainField();">調用主視窗變數</a>
    <a href="#" onClick="callMainHtml();">調用子iframe組件</a>   
    <input id="dd" type="text" value="1111111111"/>
</body>
</html>
 

兄弟iframe頁面 newIframe.htm

 代碼如下 複製代碼


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>顯示圖表</title>
<script src="/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
function callLevelFrame() {
    var ff=parent.$("#ii")[0].contentWindow.ff;
    alert(ff);
}
</script>
</head>
<body>
    <a href="#" onClick="callLevelFrame();">調用兄弟iframe</a>   
    <input id="nn" type="text" value="sdafsdfsa"/>
</body>
</html>


其實這個問題可以被大大的簡化,架構應用中有一個固定不變的視窗叫window.top,如果我們把資料緩衝到這個頁面,其下所有架構都可以擷取到,無論子頁面如何變幻。不需要採用Cookie,也不需要採用什麼HTML5本機資料庫策略,你只需要每個頁面引用一個js檔案,內容如下:

 代碼如下 複製代碼


 
var share = {

 /**
  * 跨架構資料共用介面
  * @param {String} 儲存的資料名
  * @param {Any}  將要儲存的任意資料(無此項則返回被查詢的資料)
  */
 data: function (name, value) {
  var top = window.top,
   cache = top['_CACHE'] || {};
  top['_CACHE'] = cache;
  
  return value !== undefined ? cache[name] = value : cache[name];
 },
 
 /**
  * 資料共用刪除介面
  * @param {String} 刪除的資料名
  */
 removeData: function (name) {
  var cache = window.top['_CACHE'];
  if (cache && cache[name]) delete cache[name];
 }
 
};


 

這個寥寥數行的方法可以共用任意類型的資料供各個架構頁面讀取,它與頁面名稱、層級毫無關係,就算哪天架構頁面層級被修改,你也完全不用擔心,它可正常工作。

例如,如我們可以在A頁面存入共用資料:

 代碼如下 複製代碼

share.data(‘myblog’, ‘http://www.planeart.cn’);
share.data(‘editTitle’, function (val) {
document.title = val;
});

然後某架構頁面任意取A頁面的資料

 代碼如下 複製代碼

alert(‘我的部落格地址是: ‘ + share.data(‘myblog’);
var editTitle = share.data(‘editTitle’);
editTitle(‘我已經擷取到了資料’);


執行個體誇網域作業

document.domain+iframe的設定
對於主域相同而子域不同的例子,可以通過設定document.domain的辦法來解決。具體的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html兩個檔案中分別加上document.domain = ‘a.com’;然後通過a.html檔案中建立一個iframe,去控制iframe的contentDocument,這樣兩個js檔案之間就可以“互動”了。當然這種辦法只能解決主域相同而次層網域不同的情況,如果你異想天開的把script.a.com的domian設為alibaba.com那顯然是會報錯地!代碼如下:

www.a.com上的a.html

 代碼如下 複製代碼
document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.a.com/b.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
    var doc = ifr.contentDocument || ifr.contentWindow.document;
    // 在這裡操縱b.html
    alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
};

script.a.com上的b.html

document.domain = 'a.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。

問題:
1、安全性,當一個網站(b.a.com)被攻擊後,另一個網站(c.a.com)會引起安全性漏洞。
2、如果一個頁面中引入多個iframe,要想能夠操作所有iframe,必須都得設定相同domain。
2、動態建立script
雖然瀏覽器預設禁止了跨域訪問,但並不禁止在頁面中引用其他域的JS檔案,並可以自由執行引入的JS檔案中的function(包括操作cookie、Dom等等)。根據這一點,可以方便地通過建立script節點的方法來實現完全跨域的通訊。具體的做法可以參考YUI的Get Utility

這裡判斷script節點載入完畢還是蠻有意思的:ie只能通過script的readystatechange屬性,其它瀏覽器是script的load事件。以下是部分判斷script載入完畢的方法。

 代碼如下 複製代碼
js.onload = js.onreadystatechange = function() {
    if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
        // callback在此處執行
        js.onload = js.onreadystatechange = null;
    }
};

3、利用iframe和location.hash
這個辦法比較繞,但是可以解決完全跨域情況下的腳步置換問題。原理是利用location.hash來進行傳值。在url: http://a.com#helloword中的‘#helloworld’就是location.hash,改變hash並不會導致頁面重新整理,所以可以利用hash值來進行資料傳遞,當然資料容量是有限的。假設網域名稱a.com下的檔案cs1.html要和111cn.net網域名稱下的cs2.html傳遞資訊,cs1.html首先建立自動建立一個隱藏的iframe,iframe的src指向111cn.net網域名稱下的cs2.html頁面,這時的hash值可以做參數傳遞用。cs2.html響應請求後再將通過修改cs1.html的hash值來傳遞資料(由於兩個頁面不在同一個域下IE、Chrome不允許修改parent.location.hash的值,所以要藉助於a.com網域名稱下的一個代理iframe;Firefox可以修改)。同時在cs1.html上加一個定時器,隔一段時間來判斷location.hash的值有沒有變化,一點有變化則擷取擷取hash值。代碼如下:

先是a.com下的檔案cs1.html檔案:

 代碼如下 複製代碼

function startRequest(){
    var ifr = document.createElement('iframe');
    ifr.style.display = 'none';
    ifr.src = 'http://www.111cn.net/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) {};
}
setInterval(checkHash, 2000);

111cn.net網域名稱下的cs2.html:

 代碼如下 複製代碼

//類比一個簡單的參數處理操作
switch(location.hash){
    case '#paramdo':
        callBack();
        break;
    case '#paramset':
        //do something……
        break;
}

function callBack(){
    try {
        parent.location.hash = 'somedata';
    } catch (e) {
        // ie、chrome的安全機制無法修改parent.location.hash,
        // 所以要利用一個中間的cnblogs域下的代理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);
    }
}

.com下的網域名稱cs3.html

//因為parent.parent和自身屬於同一個域,所以可以改變其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);當然這樣做也存在很多缺點,諸如資料直接暴露在了url中,資料容量和類型都有限等

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.