• window.postMessage实现网页间通信


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

    一、安装live-server

    要想实现跨窗口通信,必须要在服务器上运行,直接用浏览器打开HTML文件只能处理单个文件,窗口之间无法通信。

    npm install -g live-server
    

    使用命令live-server进行启动。

    安装live-server,在任意位置启动服务器。

    在服务器中启动之后,会看见文档中多了一个script标签。这段代码是由live-server插入的。当运行在后台的live-server检测到文件变化,就会通过websockt向网页发送“reload”消息,从而可以实现浏览器中的网页总是实时的响应文件的变更。

    	// <![CDATA[  <-- For SVG support
    	if ('WebSocket' in window) {
    		(function() {
    			function refreshCSS() {
    				var sheets = [].slice.call(document.getElementsByTagName("link"));
    				var head = document.getElementsByTagName("head")[0];
    				for (var i = 0; i < sheets.length; ++i) {
    					var elem = sheets[i];
    					head.removeChild(elem);
    					var rel = elem.rel;
    					if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
    						var url = elem.href.replace(/(&|?)_cacheOverride=d+/, '');
    						elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
    					}
    					head.appendChild(elem);
    				}
    			}
    			var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
    			var address = protocol + window.location.host + window.location.pathname + '/ws';
    			var socket = new WebSocket(address);
    			socket.onmessage = function(msg) {
    				if (msg.data == 'reload') window.location.reload();
    				else if (msg.data == 'refreshcss') refreshCSS();
    			};
    			console.log('Live reload enabled.');
    		})();
    	}
    	// ]]>
    

    二、基础知识

    MessageEvent有以下几个属性:

    • data:从其他window中传递过来的对象
    • origin:调用 postMessage 时消息发送方窗口的 origin
    • source:对发送消息的窗口对象的引用; 您可以使用此来在具有不同origin的两个窗口之间建立双向通信。

    在发送数据窗口执行:otherWindow.postMessage(msg,origin)

    • otherWindow:表示接受数据的窗口的window对象,包括iframe的子窗口和通过window.open打开的新窗口。
    • msg表示要发送的数据,包扩字符串和对象(ie9以下不支持,可以利用字符串和json互换)。
    • origin表示接收的域名。

    三、最简单的一个demo

    父窗口打开一个子窗口,然后询问子窗口:“吃饭了吗”,子窗口回复父窗口:“吃了”
    father.html

    <html>
    
    <body>
    
    </body>
    <script>
        window.addEventListener("message", function(e) {
            document.querySelector("body").appendChild(document.createTextNode('son say: ' + e.data))
        })
        var son = window.open("son.html")
        son.onload = function() {//必须得要等到儿子加载完成才可以说话
            son.postMessage("吃饭了吗", location.href)
        }
    </script>
    
    </html>
    
    

    son.html

    <html>
    
    <body>
    
    </body>
    <script>
        window.addEventListener("message", function() {
            console.log(event)
            document.querySelector("body").appendChild(document.createTextNode("father say: " + event.data))
            event.source.postMessage("吃了", event.origin)
        })
    </script>
    
    </html>
    

    四、一个网页聊天系统

    father.html

    <html>
    
    <head>
        <style>
            textarea,
            input {
                 80%;
                font-size: 20px;
                font-family: "Consolas";
            }
            
            textarea {
                height: 80%;
            }
            
            input {
                height: 10%;
            }
        </style>
    </head>
    
    <body>
        <div style="text-align:center">
            <textarea readonly></textarea>
            <input type="text" style="margin-top:10px" onkeydown="keydown()">
        </div>
    </body>
    <script>
        function $(sel) {
            return document.querySelector(sel)
        }
        window.addEventListener("message", function() {
            $("textarea").value += "
    son say: " + event.data
        })
        var son = window.open("myson.html")
    
        function keydown() { //这里不需要传递参数,直接使用event就可以
            if (event.keyCode == 13) {
                son.postMessage($("input").value, location.href)
                $("textarea").value += "
    我说:" + $("input").value
                $("input").value = ""
                event.preventDefault
            }
        }
    </script>
    
    </html>
    

    myson.html

    <html>
    
    <head>
        <style>
            textarea,
            input {
                 80%;
                font-size: 20px;
                font-family: "Consolas";
            }
            
            textarea {
                height: 80%;
            }
            
            input {
                height: 10%;
            }
        </style>
    </head>
    
    <body>
    
        <div style="text-align:center">
            <textarea readonly></textarea>
            <input type="text" style="margin-top:10px" onkeydown="keydown()">
        </div>
    </body>
    <script>
        var father = null
        window.addEventListener("message", function() {
            $("textarea").value += "
    father say: " + event.data
            if (father == null) {
                father = {
                    source: event.source,
                    origin: event.origin
                }
            }
        })
    
        function $(sel) {
            return document.querySelector(sel)
        }
    
        function keydown() { //这里不需要传递参数,直接使用event就可以
            if (event.keyCode == 13) {
                father.source.postMessage($("input").value, location.href)
                $("textarea").value += "
    我说:" + $("input").value
                $("input").value = ""
                event.preventDefault
            }
        }
    </script>
    
    </html>
    

    五、最后一个demo

    <html>
    
    <head>
        <meta charset="UTF-8">
    </head>
    
    <body>
        <input type="button" value="Open Window" onclick="openWin()" />
    </body>
    <script>
        window.addEventListener("message", function(evt) {
            var ele = document.createElement("pre")
            ele.innerText = "son say:" + JSON.stringify(evt.data)
            document.querySelector("body").appendChild(ele)
        })
    
        var popupwin = window.open("son.html");
        //onload只能执行一次,也就是如果子窗口有onload事件,可能会覆盖。
        popupwin.onload = function(e) {
            var params = "天下大势为我所控"
            var origin = location.href
            popupwin.postMessage(params, origin);
        }
        popupwin.onunload = function(e) {
            var ele = document.createElement("h1")
            ele.innerText = "儿子最后说:" + popupwin.returnValue
            document.querySelector("body").appendChild(ele)
        }
    </script>
    
    </html>
    

    son.html

    <html>
    
    <head>
        <title>popup window</title>
    </head>
    
    <body>
        <button onclick="closeWin()">点我返回</button>
        <div id="show"></div>
    </body>
    <script>
        function closeWin() {
            window.returnValue = "这是返回值";
            window.close();
        }
        //HTML DOM fully loaded, and fired window.onload later. 
        document.onreadystatechange = function() {
            if (document.readyState === 'complete') {
                window.addEventListener('message', function(event) {
                    document.querySelector("#show").appendChild(document.createTextNode("father say:" + e.data))
                    event.source.postMessage("what's the fuck", event.origin)
                });
            }
        };
    </script>
    
    </html>
    

    六、安全问题

    如果您不希望从其他网站接收message,请不要为message事件添加任何事件侦听器。
    如果您确实希望从其他网站接收message,请始终使用origin和source属性验证发件人的身份。
    当您使用postMessage将数据发送到其他窗口时,始终指定精确的目标origin,而不是*。

    参考资料

    https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

  • 相关阅读:
    HOJ 2139 Spiderman's workout(动态规划)
    FZU 2107 Hua Rong Dao(dfs)
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/7764721.html
Copyright © 2020-2023  润新知