前言介绍
在工作中就出现的这种问题,开发的产品的页面需要嵌入到公司中其他产品中,因为是不同的产品,属于不同的系统,最简单的方式就是iframe和window.open()的方式。
一、使用iframe嵌入别人的网站
<iframe src="http://www.otherwebsite.com" width="100%" height="600"></iframe>
但是,如果我们将一个非同源的网站嵌入到我们的网站中,就会出现跨域问题。
1、iframe为什么支持跨域
iframe标签支持跨域是因为iframe在浏览器中是作为一个独立的页面存在的,它有自己的window对象、document对象和location对象。
2、iframe跨域问题
当我们在一个网站中使用iframe嵌入来自不同源的网页时,会出现访问限制的问题。比如,在A网站中嵌入B网站的页面,如果B网站有对应访问限制,那么A网站就无法访问B网站页面的内容。这是因为浏览器秉承同源策略的原则,只有在协议、域名、端口这三个方面相同的情况下才可以访问。
3、iframe跨域加载页面
在iframe的src属性中可以指定一个跨域的页面来进行加载,如下所示:
<iframe src="http://www.otherwebsite.com" width="100%" height="600"></iframe>
但是,如果跨域页面的服务器设置了相关的访问控制,可能导致页面无法加载,这时需要在服务器端进行相应的设置以允许访问。
4、iframe跨域登录
在一个网站中使用iframe嵌入来自不同源的网站时,如果需要在iframe中进行登录操作,需要使用到postMessage这个API来进行消息的传递。
window.parent.postMessage("login", "http://www.otherwebsite.com");
在被嵌入的网站中,需要添加相应的监听事件来接收消息并进行处理。
window.addEventListener('message',function(evt) { if(evt.origin !== 'http://www.mywebsite.com') return; if(evt.data === 'login') { // 处理登录操作 } });
5、iframe跨域高度自适应
在iframe中嵌入一个不同源的网页时,可能会出现高度无法自适应的问题。解决这个问题可以使用window.postMessage API来进行消息的传递。iframe中的页面需要先获取自身的高度并发送给父页面。
let height = document.documentElement.scrollHeight;
window.parent.postMessage(height, "http://www.parentwebsite.com");
在父页面中需要添加相应的监听事件来接收消息并进行处理,将iframe的高度设置为接收到的高度即可。
window.addEventListener('message',function(evt) { if(evt.origin !== 'http://www.childwebsite.com') return; let height = evt.data; document.getElementById('iframe').style.height = height + 'px'; });
6、iframe跨域获取内容
在一个网站中使用iframe嵌入来自不同源的网站时,如果需要获取嵌入页面中的内容,需要使用到window.postMessage API。
window.frames['iframe'].postMessage("getContent", "http://www.childwebsite.com");
在被嵌入的网站中,需要添加相应的监听事件来接收消息并进行处理。
window.addEventListener('message',function(evt) { if(evt.origin !== 'http://www.parentwebsite.com') return; if(evt.data === 'getContent') { let content = document.getElementById('content').innerHTML; window.parent.postMessage(content, "http://www.parentwebsite.com"); } });
7、iframe跨域解决方案
解决iframe跨域问题的方式有以下几种:
1、使用postMessage API进行消息传递;
2、在服务器端设置Access-Control-Allow-Origin头信息,允许跨域访问;
3、使用JSONP方式获取数据;
4、在父页面中使用代理页面,将请求发送给代理页面,代理页面再将请求发送给另一个域名的服务器,在代理页面中处理返回结果并将结果发送给父页面。
8、iframe跨域修改样式
在一个网站中使用iframe嵌入来自不同源的网站时,需要修改嵌入页面的样式时,可以使用postMessage API进行消息传递,将需要修改的样式信息传递给iframe页面。
window.frames['iframe'].postMessage({type: 'updateStyle', cssText: 'body {background-color: red;}'}, "http://www.childwebsite.com");
在被嵌入的网站中,需要添加相应的监听事件来接收消息并进行处理。
window.addEventListener('message',function(evt) { if(evt.origin !== 'http://www.parentwebsite.com') return; if(evt.data.type === 'updateStyle') { let cssText = evt.data.cssText; let style = document.createElement('style'); style.innerHTML = cssText; document.head.appendChild(style); window.parent.postMessage('style updated', "http://www.parentwebsite.com"); } });
二、使用window.open()打开窗口展现别人的网站
window.open()的参数介绍
对于window.open()一般可以设置三个参数,这里就简单介绍了,如果需要更深入的了解就请自己查找资料
-
第一个参数,打开新窗口的url地址
-
第二个参数,给新窗口的名字(name),并不是新窗口在窗口显示的title,在窗口下,通过window.name的方式拿到
- 这里也可以设置
_self
(在旧窗口打开新窗口),_blank
(重新打开新窗口,默认就是该模式)
- 这里也可以设置
-
第三个参数,设置打开新窗口的宽高等
一般设置'left=100,top=100,width=400,height=400',四个参数,其他参数可能有浏览器兼容问题
返回值——新窗口的window引用
这时就有个疑问了,在设置第二参数时,我又想设置_self又想给新窗口设置name怎么办?
可以使用如下方式:
var targetWindow = window.open('', '_self') targetWindow.name = 'demo' targetWindow.location.href = 'http://localhost:8081/'
你会想这样写这么麻烦,下面这么写不就很简单啊
var targetWindow = window.open('http://localhost:8081/', '_self') targetWindow.name = 'demo'
这种方式有个问题,就是window.open()的页面跳转是异步的,可能是先设置name,但是页面并没有跳转,这时在新页面去取name就是''(原本的name就是'')了
如果使用第一种方式的话就没有这种问题,先跳转的是空页面,设置name属性后再页面跳转
1.使用url携带参数的形式
可能最容易想到的方式就是使用url上携带参数的形式了,但是这种方式对于传递多种数据是不方便的,而且安全性也是个问题
2.使用postMessage的方式(使用环境:Vue)
通过查找资料发现了这种比较有意思的方式,这种方式竟然对于跨域也是可以解决的,这不正合我意。
postMessage常用参数
- 第一个参数,就是传递的消息message,可以使用字符串,信息过多可以使用JSON.stringify()的方式
- 第二个参数,就是发送的url地址,也可以使用*来代替,但是不安全
发送方使用postMessage,接收方绑定message事件
window.addEventListener("message",(e) => { // 判断是否是旧窗口发过来的,这个if判断是必须的,然后会多接收一些不想接收的消息,就是信息还没有发送过来,绑定message事件会有默认信息 if (e.origin !== "http://localhost:8080") return; // e.data——接收到的信息 // e.origin——发送发的url地址,如果没有if判断,就会返回接收方的url(默认信息) // e.source——发送方的window引用,如果没有if判断,就会返回接收方的window(默认信息) // e.origin和e.source结合可以让接收方向发送方发送信息,从而达到双向通信 console.log(e.data) })
我就直接介绍跨域的方式如何使用,对于同源的方式也可以使用该方式,也有其他方式。
我想要的,
旧窗口把信息传给新窗口
旧窗口
// http://localhost:8080/ <template> <div id="app"> <button @click="open">打开新窗口</button> </div> </template> export default { name: 'App', data () { this.targetWindow = null return { } }, methods: { open() { this.targetWindow = window.open('http://localhost:8081/', '_blank', 'left=100,top=100,width=400,height=400') // 为什么加定时器,主要是为了防止window.open()异步加载,页面没有加载出来,就把消息发送出去了,有更好的方式也可以使用其他方式 setTimeout(() => { this.targetWindow.postMessage('旧窗口向新窗口发送的消息', 'http://localhost:8081/') }, 1000) } } } </script>
新窗口
// http://localhost:8081/ <template> <div id="app"> 新窗口 </div> </template> export default { name: 'App', mounted() { window.addEventListener("message",(e) => { if (e.origin !== "http://localhost:8080") return; //发送方发送的信息 console.log(e.data) }) } }
旧窗口可以向新窗口发信息,新窗口也可以发送信息给旧窗口
旧窗口
// http://localhost:8080/ <template> <div id="app"> <button @click="open">打开新窗口</button> <button @click="sendNew">向新窗口传消息</button> 旧窗口接收到的信息:{{ text }} </div> </template> export default { name: 'App', data () { this.targetWindow = null return { text: '' } }, mounted() { window.addEventListener('message',(e) => { if (e.origin !== "http://localhost:8081/") return; console.log(e.data) this.text += e.data }) }, methods: { open() { this.targetWindow = window.open('http://192.168.3.76:8081/', '_blank', 'left=100,top=100,width=400,height=400') setTimeout(() => { this.targetWindow.postMessage('旧窗口向新窗口发送的消息', 'http://192.168.3.76:8081/') }, 1000) }, sendNew() { this.targetWindow.postMessage('旧窗口通过按钮发送给新窗口的消息', 'http://localhost:8081/') } } } </script>
新窗口
//http://localhost:8081/ <template> <div id="app"> 新窗口 <button @click="sendOld">向旧窗口发送消息</button> <!-- 接收旧窗口发送的消息 --> 接收旧窗口发送的消息:{{ text }} </div> </template> export default { name: 'App', components: { }, data() { this.oldWindow = null this.oldOrigin = null return { text: '' } }, mounted() { window.addEventListener("message",(e) => { if (e.origin !== "http://localhost:8080") return; this.text += e.data this.oldWindow = e.source this.oldOrigin = e.origin }) console.log(window.name) }, methods: { sendOld() { this.oldWindow.postMessage('新窗口通过按钮给旧窗口发送的消息', this.oldOrigin) } } }
看到这里你可能发现有段代码很怪,为什么有些数据声明在return上面的,这么做是因为让这个数据失去响应式,如果声明在return内是有响应式的,这时this.targetWindow = window.open()在控制台会出现跨域的报错。原因是因为给它赋值是打开子窗口的window,赋值会就会监听targetWindow,就相当于在父窗口去对子窗口做操作,就造成了跨域的问题。
3.使用window.name的方式传递信息
利用window.open()的第二个参数,把信息传给新窗口
旧窗口
window.open('http://localhost:8081/','要传递的信息')
新窗口
console.log(window.name)
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。
本文地址:http://www.tukus.cn/cydz/yong/2024-12-06/261.html