Iframe父子窗口通信

1,716 阅读2分钟

1、准备

结构说明:在parent.html中使用iframe加载son.html和daughter.html。
分别在父窗口中获取子窗口的方法和变量;在子窗口中获取父窗口的变量和方法。
son.html跳转到daughter.html,观察parent.html的变化。
同时,父窗口监听子窗口的变量变化, 以及子窗口监听父窗口的变量变化的机制。
最后,iframe的宽高适配子窗口。

1.1 parent.html中使用iframe

    <iframe id="if" name="if" scrolling="no" src="son.html" onload="load()"></iframe>

2、父子窗口获取彼此变量和方法

2.1 父窗口中获取子窗口的方法和变量

document.getElementById('if').contentWindow.list_son;       // 变量
document.getElementById('if').contentWindow.son_fun(); // 方法

2.2 子窗口中获取父窗口的方法和变量

window.parent.list_parent;  // 变量
window.parent.parent_fun(); // 方法

3、父子窗口分别监听彼此变量的变化

3.1 子窗口中监听父窗口变量变化

在父窗口中,变量array的内容移除一个,立即通知子窗口,而子窗口在加载时一直监听着消息。

  • parent.html
list_parent.pop();
document.getElementById('if').contentWindow.postMessage({  // 参考:https://blog.csdn.net/it_java_shuai/article/details/109443125
        msg: list_parent
},"*")
  • son.html
window.addEventListener("message",function(event){
    var data =event.data;

    console.log("son --- 监听到父窗口的变量的变化" + JSON.stringify(data));
});

3.2 父窗口中监听子窗口变量变化

在父窗口中获取子窗口的值,并且改变,通知父窗口。

  • parent.html
// 获取子窗口变量并修改
console.log(document.getElementById('if').contentWindow.list_son);
document.getElementById('if').contentWindow.list_son.pop();

// 这是在父窗口中改变了子窗口的变量的值,并通知到父窗口。
document.getElementById('if').contentWindow.parent.postMessage({
    msg: document.getElementById('if').contentWindow.list_son
},"*");

////////////////////////////////////////////////////////////////
//父页面监听:
window.addEventListener("message", function(event){
    console.log(event);
    var data = event.data;
    console.log("parent --- 监听到子窗口的变量的变化" + JSON.stringify(data));
})

4、子窗口跳转到另一个子窗口的情况

在父窗口加载iframe时,打印日志。

  • parent.html
function load() {
    console.log('加载。。。');
}

从son.html跳转到daughter.html,再返回到son.html。打印日志如下:

image.png

子窗口每一次跳转都会使用iframe重新加载不同的html。所以也可以使用DOM节点修改是src来跳转,并且可以携带参数。如:

  • daughter.html
  window.parent.document.getElementById('if').src='/son.html?msg=xixi';
  • son.html
let url = location.search; //获取url中"?"符后的字串
if(url.length>0) { //判断是否携带参数
    let params = {};
    if (url.indexOf('?') != -1) {
        this.isShwoInput = true;
        let str = url.substr(url.indexOf('?') + 1);
        let strs = str.split('&');
        for (let i = 0; i < strs.length; i++) {
            params[strs[i].split('=')[0]] = decodeURI(strs[i].split('=')[1]);
        }
    }
    // return params;
    console.log(params);
}

5、iframe的宽高适配子窗口

在iframe在load完html后,获取子窗口的宽高来决定iframe的宽高。

  • parent.html
var scrollHeight = document.getElementById('if').contentWindow.document.body.scrollHeight;
var scrollWidth = document.getElementById('if').contentWindow.document.body.scrollWidth;

document.getElementById('if').width = scrollWidth;
document.getElementById('if').height = scrollHeight;

这里顺便说明下onload的触发时机

onload函数的执行并不是我们通常所理解的浏览器构建完html页面对应的DOM树后立刻执行,而是要等到页面中所引用的图片等外部资源 完全下载完成后并且在浏览器中显示才执行。

6、源码

  • parent.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title>Title</title>
    <script>
        var list_parent = new Array();
        list_parent.push("刘备");
        list_parent.push("关羽");
        list_parent.push("张飞");

        function parent_fun() {
            return list_parent;
        }

        function load() {
            console.log('加载。。。');
            // 自适应子窗口的宽高
            var scrollHeight = document.getElementById('if').contentWindow.document.body.scrollHeight;
            var scrollWidth = document.getElementById('if').contentWindow.document.body.scrollWidth;

            document.getElementById('if').width = scrollWidth;
            document.getElementById('if').height = scrollHeight;
            console.log(document.readyState); // Interactive. 可以接收到部分响应数据,网上说这个状态时,数据是只读的,但是我修改了数据,发现也是生效的

        }

        function get_son_var_fun() {
            console.log('加载。。。');

            // 获取子窗口变量和方法
            console.log(document.getElementById('if').contentWindow.list_son);
            document.getElementById('if').contentWindow.list_son.pop();

            // 这是在父窗口中改变了子窗口的变量的值,并通知到父窗口。
            document.getElementById('if').contentWindow.parent.postMessage({
                msg: document.getElementById('if').contentWindow.list_son
            },"*");

            console.log(document.getElementById('if').contentWindow.son_fun());

            console.log(document.readyState); // Interactive. 可以接收到部分响应数据,网上说这个状态时,数据是只读的,但是我修改了数据,发现也是生效的

        }

        function changeVar() {
            list_parent.pop();
            document.getElementById('if').contentWindow.postMessage({  // 参考:https://blog.csdn.net/it_java_shuai/article/details/109443125
                    msg: list_parent
            },"*")
        }


        //父页面监听:
        window.addEventListener("message", function(event){
            console.log(event);
            var data = event.data;
            console.log("parent --- 监听到子窗口的变量的变化" + JSON.stringify(data));
        })


    </script>
</head>
<body>
<h1>我是父窗口</h1>
<!--
    Iframe还未被加载完成就调用里面的方法或者变量,会报错,判断iframe是否被加载完成的方法有:
    1、document.readyState=="complete"
    2、onload事件(推荐)

-->
    <button id="getVarAndFun" type="button" onclick="get_son_var_fun()">获取子窗口的变量和方法</button>

    <button id="changeVar" type="button" onclick="changeVar()">改变父窗口的值</button>
    <iframe id="if" name="if" scrolling="no" src="son.html" onload="load()"></iframe>
</body>
</html>
  • son.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<style>
    html,body {
        margin: 0;
        padding: 0;
        width: 100px;
        height: 200px;
    }
</style>

<script type="text/javascript">
    var list_son = new Array();
    list_son.push("曹操");
    list_son.push("司马懿");

    function son_fun() {
        return list_son;
    }

    function getParentVar() {
        // alert("getParentVar");
       console.log(window.parent.list_parent);
    }

    function getParentFun() {
        console.log(window.parent.parent_fun());
    }

    function load_son() {
        let url = location.search; //获取url中"?"符后的字串
        if(url.length>0) { //判断是否携带参数
            let params = {};
            if (url.indexOf('?') != -1) {
                this.isShwoInput = true;
                let str = url.substr(url.indexOf('?') + 1);
                let strs = str.split('&');
                for (let i = 0; i < strs.length; i++) {
                    params[strs[i].split('=')[0]] = decodeURI(strs[i].split('=')[1]);
                }
            }
            // return params;
            console.log(params);
        }
    }

    window.addEventListener("message",function(event){
        var data =event.data;

        console.log("son --- 监听到父窗口的变量的变化" + JSON.stringify(data));
    });

</script>
<!--<body>-->
<body onload="load_son()">
    <div id="sonid" style="background: green;">
        <button id="getVar" type="button" onclick="getParentVar()">获取父窗口变量</button>
        <button id="getFun" type="button" onclick="getParentFun()">获取父窗口方法</button>
        <br>
        <a href="daughter.html">跳转另一子窗口</a>
        son
    </div>
</body>
</html>
  • daughter.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        html,body {
            margin: 0;
            padding: 0;
            width: 150px;
            height: 200px;
        }
    </style>
    <script>
        function goback() {
            // window.history.back();
            window.parent.document.getElementById('if').src='son.html?msg=xixi';
        }

        window.addEventListener("message",function(event){
            var data =event.data;
            console.log("daughter 监听到父窗口的变量的变化--- " + JSON.stringify(data));

        });
    </script>

</head>

<body>
    <div id="sonid" style="background: pink; width: 100px; height: 200px">
        <button id="back" type="button" onclick="goback()">返回上一个窗口</button>

        daughter
</div>
</body>
</html>

参考

blog.csdn.net/weixin_4404… blog.csdn.net/ios0213/art… blog.csdn.net/it_java_shu…