浅析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'; // 隐藏
}

  这样,各个页面窗口不互相影响,即使新开两个页面,也能独立记录是否第一次进入页面,还是刷新。

  有其他妙用欢迎不吝赐教。

posted @ 2021-10-09 21:49  古兰精  阅读(1170)  评论(0编辑  收藏  举报