1. 程式人生 > 其它 >淺析window.name屬性介紹、利用window.name+隱藏iframe獲取跨域資料的實現原理、應用場景(資料傳遞、判斷是否第一次進入視窗)

淺析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'; // 隱藏
}

  這樣,各個頁面視窗不互相影響,即使新開兩個頁面,也能獨立記錄是否第一次進入頁面,還是重新整理。

  有其他妙用歡迎不吝賜教。