跨域
方法 1:document.domain
修改 document.domain 来跨子域,当前页面与 iframe 页面都设置相同的 domain
<!-- 父页面 -->
<iframe id="iframe" src="son.html" onload="test()"></iframe>
// 父页面
document.domain = 'aaa';
function test() {
let win = document.getElementById('iframe').contentWindow;
win.a();
}
// 子页面
document.domain = 'aaa';
function a() {
console.log('子页面');
}
方法 2:window.name
window.name 大小可达 2m
window 对象有个 name 属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个 window.name 的,每个页面对 window.name 都有读写的权限,window.name 是持久存在一个窗口载入过的所有页面中的,并不会因 新页面的载入而进行重置。
即我们在 http://www.baidu.com 页面的控制台设置window.name="name=123",然后我们在控制台修改 window.location.href="http://www.youku.com",跳转页面后我们在控制台打印 window.name,我们发现结果为我们刚才设置的 name=123,利用此原理我们可以利用 window.name 来传递信息
获取流程如下
- 子页面先设置好要获取的数据
- iframe 嵌入子页面,此时 iframe 可以获取到子页面的数据
- 父页面和 iframe 不同源无法直接获取,因此将 iframe 跳转到与父页面同源的页面(注意 iframe 初次加载与跳转页面都会执行 onload 事件,因此下面代码中的 loadData 方法是可以正常运行的)
- 根据 window.name 的特性,页面跳转不会改变其值,因此跳转后父页面即可通过 iframe 获取数据了
// 父页面
function test() {
let boo = false;
let iframe = document.createElement('iframe');
let loadData = function () {
if (boo) {
// 获取子页面 window.name,即要获取的数据
let data = iframe.contentWindow.name;
// 获取到数据后将隐藏的iframe去除
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
} else {
boo = true;
// 随意写,与当前页面同源即可
iframe.contentWindow.location.href = 'about:blank';
}
};
iframe.src = 'son.html';
if (iframe.attachEvent) {
iframe.attachEvent('onload', loadData);
} else {
iframe.onload = loadData;
}
document.body.appendChild(iframe);
}
test();
// 子页面
window.name = 'son';
方法 3:location.hash
子页面修改父页面 src 的 hash 值,通过该属性传递数据,但长度有限
- 首先准备 3 个页面:a、b、c,a、c 同源,b 不同源
- a 嵌入 b,b 嵌入 c,a 页面定义一个方法供 c 调用,用以返回数据
- b 监听自身 hash 改变,然后更改 c 的 hash
- c 监听自身 hash 改变,然后调用 a 定义的方法,传回数据
<!-- a 页面 -->
<iframe id="iframe" src="b.html"></iframe>
<!-- b 页面 -->
<iframe id="iframe" src="c.html"></iframe>
// a 页面
let iframe = document.getElementById('iframe');
setTimeout(() => {
iframe.src = iframe.src + '#user=admin';
}, 1000);
function onCallback(res) {
console.log('data from c.html -> ' + res);
}
// b 页面
let iframe = document.getElementById('iframe');
window.onhashchange = function () {
iframe.src = iframe.src + location.hash;
};
// c 页面
window.onhashchange = function () {
window.parent.parent.onCallback(
'hello:' + location.hash.replace('#user=', '')
);
};
方法 4:postMessage
// 父页面
window.onload = function () {
let iframe = document.getElementById('iframe');
iframe.contentWindow.postMessage('aaa', 'url');
window.addEventListener('message', receiveMessage, false);
function receiveMessage(e) {
console.log(e.data);
}
};
// 子页面
window.addEventListener('message', receiveMessage, false);
function receiveMessage(e) {
console.log(e.data);
e.source.postMessage({ a: 1 }, e.origin);
}
方法 5:jsonp
利用 script 文件不跨域的特性
其中 callback 是服务端定义的方法,名称随意,双方确定好即可
<!-- 父页面 -->
<script>
function callbackFn(data) {
console.log(data);
}
</script>
<script src="jsonp.js?callback=callbackFn"></script>
// jsonp.js
callbackFn({
code: 1,
data: [{ id: 1, name: 2 }],
});