一、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>
有时候我们的需求是在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'; // 隐藏
}
这样,各个页面窗口不互相影响,即使新开两个页面,也能独立记录是否第一次进入页面,还是刷新。
有其他妙用欢迎不吝赐教。