淺析window.name屬性介紹、利用window.name+隱藏iframe獲取跨域資料的實現原理、應用場景(資料傳遞、判斷是否第一次進入視窗)
一、window下自帶的 name 屬性
不知道大家有沒有發現這樣一種情況:在控制檯裡直接輸出未宣告變數,正常情況應該是會報錯的,而且宣告未賦值的變數輸出應該是undefined;但是偏偏就個別特例,就是name屬性。
其實 window 自身就帶有 name 這個屬性,在控制檯輸入window可以可以看到。
window.name直譯過來是視窗名字,主要用於為超連結和表單設定目標(targets)。
什麼意思呢,我們做個案例:
// 第一個頁面
<a href="./demo2.html" target="hello world">跳轉</a>
// 第二個頁面
document.write( window.name + "<br>" + name )
我們從第一個頁面跳轉到第二個頁面後會看到頁面上有 2 個 hello world。
這裡我們就可以看出,第一個網頁的a標籤通過target屬性將值賦值給第二個視窗的name屬性,這樣第二個網頁的name屬性就有值了。
注意:
1、這裡提一下 window.open( strUrl , strWindowName , [strWindowFeatures] ) 的第二值也是可以給新視窗設定 window.name
2、window.name表示當前視窗的名字,而非網頁的名字,網頁的名字需要使用: document.title;
3、window.name 一般是空的字串,他的作用其實是配合超連結和表單的target來使用的,也就是跳轉時將當前視窗的資訊帶過去。只要這個視窗不關閉,那從這個視窗開啟的其他視窗都能獲得這個視窗的 window.name。
二、window.name 跨域
頁面在瀏覽器端展示的時候,我們總能在控制檯拿到一個全域性變數window,該變數有一個name屬性,其有以下特徵:
1、每個視窗都有獨立的window.name與之對應;
2、在一個視窗的生命週期中(被關閉前),視窗載入的所有頁面同時共享一個window.name,每個頁面對window.name都有讀寫的許可權;
3、window.name一直存在與當前視窗,即使是有新的頁面載入也不會改變window.name的值;
4、window.name可以儲存不超過2M的資料,資料格式按需自定義。
下面我們就驗證一下同一個視窗下,頁面重新載入,window.name 仍然不變
<script>
// 這裡是要傳輸的資料,大小一般為2M,IE和firefox下可以大至32M左右
// 資料格式可以自定義,如json、字串
window.name = "這是a頁面的內容";
setTimeout(function(){
window.location.href= b.html;
console.log(window.name); //"這是a頁面的內容"
},2000);
</script>
我們再控制檯設定 name = 123,然後更換連結重新整理,在到控制檯看 name 還是 123。
有時候我們的需求是在https://localhost/a.html頁面內,獲得"https://xxx.github.io/xxx/"上的資料,並且頁面不能進行重新整理。
對於這種需求,我們不能通過window.location.href
更新頁面來獲得資料,我們可以用一個隱藏的iframe作為中間的代理,iframe的src為"https://xxx.github.io/xxx/",在iframe頁面載入完畢的時候,我們再讓iframe與當前頁面屬於同一個域下,我們就可以拿到window.name
了。
<script>
function load () {
var iframe = document.getElementById('iframe');
iframe.onload = function () {
var window = iframe.contentWindow;
console.log(window.name);
}
iframe.src = 'about:blank'; //讓url地址改變,與當前頁面同源,可以任意寫,保持同源就好
}
</script>
<iframe id="iframe" src="https://xxx.github.io/xxx/" onload="load()"></iframe>
跨域原理:用 window.name 實現跨域,就是利用他的一個特點,就是在一個頁面載入的其他頁面將共享一個window.name,其他頁面都有對其的讀寫許可權,即使其他頁面載入新頁面,其window.name也不變。
下面有三個頁面:第一個頁面放在域名localhost下
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>頁面一</title> </head> <body> <h1>頁面一</h1> <script> var iframe = document.createElement('iframe');//工具人 iframe.style.display = "none";//工具人隱藏在背後默默付出 var flag = false; iframe.onload = function () { if ( flag ) { var data = iframe.contentWindow.name;//contentWindow.name可以拿到iframe的視窗name值 console.log(data); iframe.contentWindow.close();//關閉隱藏的頁面 document.body.removeChild(iframe);//刪除隱藏的頁面 } else { flag = true; iframe.contentWindow.location = 'http://localhost/demo2.html';
//這裡因為瀏覽器同源策略,需要將連結改成與頁面一同源的頁面(也就是頁面二),這裡會再次觸發load事件 } } iframe.src = 'http://data/data.html';//跨域,這裡視窗已經拿到name,所以上面更換地址後name的值依舊存在 document.body.appendChild(iframe); </script> </body> </html>
第二個頁面是空頁面,也是在localhost域名下
第三個頁面是資料頁面,放在data域名下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>data</title>
</head>
<body>
<h1>資料</h1>
<script>
window.name = '{data:"資料"}';//將資料存到window.name裡
</script>
</body>
</html>
給 隱藏iframe 賦值跨域的連結,載入完後觸發load事件,此時iframe已經拿到資料放在window.name裡,因為瀏覽器同源策略沒法直接拿 iframe 的 name 值,所以將 iframe 的地址改成同域名下的一個網頁,在用 contentWindow 方法獲取 iframe 的 name 值拿資料。
三、應用場景
總體感覺應用場景不多,下面這 2 個場景使用還不錯:
1、利用 window.name 進行頁面間的資料傳遞,這個就不多說了,具體情況具體考慮吧;
2、Window.name 判斷頁面是第一次進入還是重新整理
之前公司有個需求,扣費資訊在第一次進入頁面視窗彈出,若使用者重新整理此頁面視窗則不應該彈出消費資訊。使用cookie不能滿足這個需求,因為如果使用者開啟第二個視窗,也是需要第一次彈出扣費資訊。覺得windw name屬性比較合適又很簡單,可以用於區分頁面是第一次進來還是重新整理。
if ( !window.name ) { // 第一次進頁面
window.name="myname";
} else{ // 非第一次進頁面
document.getElementById("div").style.display = 'none'; // 隱藏
}
這樣,各個頁面視窗不互相影響,即使新開兩個頁面,也能獨立記錄是否第一次進入頁面,還是重新整理。
有其他妙用歡迎不吝賜教。