iframe
遵守同源策略,只有父页面与嵌套页面来自同一个域名,两者才能通信。所以首先需要进行同域代理,其次需要了解一下HTMLIFrameElement.contentDocument
1、HTMLIFrameElement.contentDocument
- 使用这个方法获取页面
iframe
中的dom
对象,注意可能会有下面两种结果: - 如果
iframe
和它的父级在同一个域名下,那么这个方法返回document(是一个嵌套的浏览器上下文环境) - 如果
iframe
和它的父级不在同一个域名下,那么这个方法返回null
所以,修改前提是同域。
对于iframe
嵌入的窗口,通过document.getElementById
方法或者ref
可以拿到该窗口的DOM
节点,然后使用contentWindow
属性获得iframe
节点包含的document
对象。
2、在修改为同域后,如何在本地进行样式的调整
- 举例:
javascript
<iframe ref="iframe" :src="accessUrl"></iframe>
1、已经将页面代理到我们产品上(访问某地址即可,/eolink)
data() {
return {
accessUrl: `${location.origin}/eolink/template/upstream`
}
}
2、未将页面代理到我们产品上(需要访问具体url)
mounted() {
let url = await getSubSystemUrl(); // 返回url
this.accessUrl = url.replace(
'https://xxxxxxx',
'http://本地服务启动的地址'
);
}
- 在这时候直接访问页面是空白的,再看控制台
network
- 判定没有获取到它的静态资源
- 修改
vue.config.js
中的proxy
代理前缀iframe
的url
前缀eolink
js
'/eolink': {
secure: false,
target: '你服务器的地址',
// router: () => hotServer(),
onProxyReq(proxyReq) {
// 绕过后端的csrf验证
proxyReq.setHeader('referer', '你服务器的地址');
}
}
- 这时候代理成功,已经请求到静态资源了,一般情况下已经可以访问到页面了,如果还没页面显示,可以看看控制台是否有报错
- 如遇这种
404
就接着代理/api
- 那就再给
api
代理一次
js
'/api': {
secure: false,
target: '你服务器的地址',
onProxyReq(proxyReq) {
proxyReq.setHeader('referer', '你服务器的地址');
}
- 如果遇到跨域问题,可以本地起
nginx
进行代理转发
代码示例
js
<template>
<div class="upstream" v-loading="loading">
<iframe ref="iframe" :src="accessUrl"></iframe>
</div>
</template>
<script>
export default {
data() {
return {
accessUrl: `${location.origin}/eolink/template/upstream`,
interval: '',
loading: true
};
},
async mounted() {
this.handleIframe();
},
methods: {
handleIframe() {
const iframe = this.$refs.iframe;
iframe.style.opacity = 0;
iframe.onload = () => {
this.interval = setInterval(() => {
// 新增样式并插入节点
const head = iframe.contentWindow.document.querySelector('head');
const style = iframe.contentWindow.document.createElement('style');
style.innerHTML = `
// 修改样式的css
`;
head.appendChild(style);
// 恢复iframe的展示
this.loading = false;
iframe.style.opacity = 1;
clearInterval(this.interval);
}, 500);
// 无论页面内容是否加载出来,15秒钟后清除定时器
setTimeout(() => {
this.loading = false;
iframe.style.opacity = 1;
clearInterval(this.interval);
}, 15000);
};
}
}
};
</script>
<style lang="less" scoped>
.upstream {
height: 100%;
iframe {
border: none;
width: 100%;
height: 100%;
}
}
</style>