iframe页面跨域父子传参通信

基本概念:

window.self: 当前窗口自身的引用
window.parent: 上一级父窗口的引用
window.top: 最顶层窗口的引用
当页面中不存在 iframe 嵌套时,则三者均是当前窗口自身的引用。

同域iframe相互调用:

子页面调用父页面方法:window.parent.fatherFn();
父页面调用子页面方法: window.sonFrameName.sonFn(); (sonFrameNameiframename值)

非跨域 父调子

//父页面
<button class="b" id="b">点击button>
<iframe src="a.html" name='child' id="f">iframe>

<script>
    var ob=document.getElementById('b');
    var msg='hellow,i'm your father!!'
    ob.onclick=function(){
        if(child.document.readyState=="complete"){
            child.window.fnChild(msg); //关键
        }
    }
script>

//子页面
<script>
function fnChild (arg) {
    console.log(arg); //确实得到了 hellow,i'm your father!!
}
script>

父页面调用子页面使用 childFrameName.window.fnName(); 当然有一点很重要,你需要判断iframe 里面的东西是否加载完成,如果加载未完成就调用的话是会报错的;
判断iframe 加载是否完成有2种方法

  • childFrameName.document.readyState=="complete"来判断;
  • childFrameName.onload=function(){} 使用onload 回调函数,把调用的方法都写在这个回调函数里面;

非跨域 子调父

//在父页面
<div id="a" class="a">div>
<iframe src="a.html" name='child' id="f">iframe>

<script>
    function changeColor(){
        var oDiv=document.getElementById('a');
        oDiv.style.backgroundColor="red";
    }
script>

//在子页面
<button class="ob" onclick="c()">anniubutton>
<script>
    function c(){
        parent.window.changeColor(); //关键
    }
script>

同样的,在子页面调用父页面的方法使用 parent.window.fnName()就可以了;

这种操作难免会遇到父页面获取子页面的元素,或者子页面获取父页面的元素进行操作;

非跨域 父页面获取子页面元素操作

首先,我们有几种方法拿到子页面的window对象或者doucument 对象,(还是使用上面的html)

//原生js 获取子页面window对象
var childWindow = document.getElementById("f").contentWindow;
var childWindow = document.getElementsByTagName('f')[0].contentWindow;
//其实也就是普通的获取方法,只是后面多了一个contentWindow;
//jquery
var childWindow = $('#f').contentWindow;

//获取子页面的document对象 (假设已经通过上面的方法得到了window对象)
var frameDoc = childWindow.document;
var frameBody = frameDoc.body;
//jquery 也是跟上面的一样
var frameDoc = $(childWindow.document);

//原生获取元素
childWindow.document.getElementById('a') //上面都已经拿到了子页面的window对象,所以获取子页面的元素也就只需要想普通操作那样获取就好
childWindow.document.getElementById('a').style.color='red' //改个颜色

//jq拿子页面元素
$('#f').contents().find('#a'); //$('#f').contents 这相当于拿到了iframe 里面所有的dom;

非跨域 子页面获取父页面元素

//原生js
window.parent.document.getElementById('a'); //window.parent获取到父页面的window对象,那么接可以使用一般操作获取元素
window.parent.document.getElementById('a').style.color="red";//dom操作
//jquery
$("#a",parent.document); //$(父页面元素选择器, parent.document);
$("#a",parent.document).css('border','1px solid red');

上面的是不存在跨域的情况,但是有时候会遇到跨域情况,在这次的项目里面就是出于跨域状态下,开始看了一些资料,说是在用一个iframe做中间层去做,但是太麻烦,在这里介绍一个十分还用的方法postMessage

postMessage

window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。

postMessage十分强大,既可以子传父,也可以父穿子,并且可以突破同源限制

跨域发送信息

otherWindow.postMessage(message, targetOrigin, [transfer]);
  • otherWindow
    其他窗口的一个引用,写的是你要通信的window对象。
    例如:在iframe中向父窗口传递数据时,可以写成window.parent.postMessage()window.parent表示父窗口。

  • message
    需要传递的数据,字符串或者对象都可以。

  • targetOrigin
    表示目标窗口的源,协议+域名+端口号,如果设置为“*”,则表示可以传递给任意窗口。在发送消息的时候,如果目标窗口的协议、域名或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。例如:
    `window.parent.postMessage(‘hello world’,‘http://xxx.com:8080/index.html’)
    只有父窗口是http://xxx.com:8080时才会接受到传递的消息。

  • [transfer]
    可选参数。是一串和message 同时传递的 Transferable 对象,这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。我们一般很少用到。

跨域接收信息

需要监听的事件名为message

window.addEventListener('message', function (e) {
    console.log(e.data)  // e.data为传递过来的数据
    console.log(e.origin)  // e.origin为调用 postMessage 时消息发送方窗口的 origin(域名、协议和端口)
    console.log(e.source)  // e.source为对发送消息的窗口对象的引用,可以使用此来在具有不同origin的两个窗口之间建立双向通信
})

示例Demo

示例功能:跨域情况下,子父页面互发信息并接收。

  • 父页面代码:
<body>
	<button onClick="sendInfo()">向子窗口发送消息button>
	<iframe id="sonIframe" src="http://192.168.2.235/son.html">iframe>
    <script type="text/javascript">

        var info = {
            message: "Hello Son!"
        };
		//发送跨域信息
		function sendInfo(){
			var sonIframe= document.getElementById("sonIframe");
			sonIframe.contentWindow.postMessage(info, '*');
		}
		//接收跨域信息
		window.addEventListener('message', function(e){
				alert(e.data.message);
		}, false);
    script>
body>
  • 子页面代码
<body>
	<button onClick="sendInfo()">向父窗口发送消息button>
    <script type="text/javascript">

        var info = {
            message: "Hello Parent!"
        };
		//发送跨域信息
		function sendInfo(){
			window.parent.postMessage(info, '*');
		}
		//接收跨域信息
		window.addEventListener('message', function(e){
				alert(e.data.message);
		}, false);
    script>
body>

注意:一定是页面加载完成后再发送消息,否则会因为 iframe 未加载完成报错。
Failed to execute ‘postMessage’ on ‘DOMWindow’

iframe 加载完成示例

var iframe = document.createElement("iframe");
iframe.src = "http://www.baidu.com/";

if (!/*@cc_on!@*/0) { // if not IE
    iframe.onload = function(){
        alert("框架加载完毕.");
    };
} else {
    iframe.onreadystatechange = function(){
        if (iframe.readyState == "complete"){
            alert("框架加载完毕.");
        }
    };
}

document.body.appendChild(iframe);

//方法二
var iframe = document.createElement("iframe");
iframe.src = "http://www.baidu.com/";

if (iframe.attachEvent){
    iframe.attachEvent("onload", function(){
        alert("Local iframe is now loaded.");
    });
} else {
    iframe.onload = function(){
        alert("Local iframe is now loaded.");
    };
}

document.body.appendChild(iframe);

你可能感兴趣的:(前端,iframe,跨域通信)