两个有路由转跳关系的模块(模块A和B,AB可以通过路由互相转跳)分散在两个不同的项目中(比如迁移仓库没全迁移完,只迁移了A模块),此时后端需要联调AB模块整体功能。
此时可以借助一个父项目,把A模块和B模块通过iframe嵌入,从而实现功能的组合。
把A模块与B模块中路由转跳相关的代码修改为与父应用的通信(window.parent.postMessage
),目的是借助父应用与另一个模块通信,父应用中就可以通过接收到的路由参数拼接出目标的路由地址,然后操作另一个模块的iframe的src属性,从而完成正常的路由转跳。
index.html相当于嵌入了很多子项目的主应用,里面通过iframe嵌入了child.html以及一个哔哩哔哩主页的iframe。
child.html相当于一个子应用,它可以读取一个id,从而向主应用发送消息,主应用监听消息事件,操作b站iframe的src,从而做到子应用之间的通信。
通过live-server启动index.html与child.html
在index.html应用中:操作上方child.html里的input,输入用户id,点击按钮。观察下方iframe的变化
child.html
:
<!DOCTYPE html>
<html lang="en">
?<head>
? ?<meta charset="UTF-8" />
? ?<meta name="viewport" content="width=device-width, initial-scale=1.0" />
? ?<title>另一个iframe页面</title>
?</head>
?<body>
? ?<div>
? ? 请输入用户主页id:<input type="text" />
? ? ?<button onclick="onBtnClick()">转跳至b站指定用户主页</button>
? ?</div>
? ?<script>
? ? ?function onBtnClick() {
? ? ? ?const input = document.querySelector("input");
? ? ? ?const userId = input.value;
? ? ? ?const params = {
? ? ? ? ?targetUrl: "https://space.bilibili.com",
? ? ? ? ?userId,
? ? ? };
? ? ? ?// 当本身作为一个iframe被嵌入时,通过window.parent访问自己所在的父应用
? ? ? ?// window.parent.postMessage中的xxxWindow.postMessage方法即触发xxxWindow的message事件,第一个参数params即为传递的参数,第二个参数可以为具体的URI,只有URI与xxxWindow同源时xxxWindow才能接受到message,或者"*",表示不限制
? ? ? ?// 第二个参数为具体URI时意义需确定,总之就是同源限制
? ? ? ?window.parent.postMessage(params, "*");
? ? }
? ?</script>
?</body>
</html>
index.html
:
<!DOCTYPE html>
<html lang="en">
?<head>
? ?<meta charset="UTF-8" />
? ?<meta name="viewport" content="width=device-width, initial-scale=1.0" />
? ?<title>Document</title>
?</head>
?<style>
? ?.app {
? ? ?display: flex;
? ? ?flex-direction: column;
? ? ?height: 100vh;
? }
? ?.page2 {
? ? ?flex: 1;
? }
?</style>
?<body>
? ?<div class="app">
? ? ?<iframe
? ? ? ?src="http://127.0.0.1:5500/child.html"
? ? ? ?width="100%"
? ? ? ?height="40px"
? ? ? ?class="page1"
? ? ?></iframe>
? ? ?<div class="page2">
? ? ? ?<iframe
? ? ? ? ?width="100%"
? ? ? ? ?frameborder="no"
? ? ? ? ?height="100%"
? ? ? ? ?src="https://www.bilibili.com/"
? ? ? ?></iframe>
? ? ?</div>
? ?</div>
? ?<script>
? ? ?const page1 = document.querySelector(".page1");
? ? ?const page2 = document.querySelector(".page2");
? ? ?// 父应用监听child.html应用的message事件,并且操作b站iframe(视为另一个子应用)的src
? ? ?window.addEventListener("message", (e) => {
? ? ? ?const { targetUrl, userId } = e.data || {};
? ? ? ?if (targetUrl && userId) {
? ? ? ? ?page2.children[0].src = `${targetUrl}/${userId}`;
? ? ? }
? ? });
? ?</script>
?</body>
</html>
我们可以在父应用中在子应用的iframe的外层套一个div,这个盒子flex布局,并给iframe设置flex: 1;
样式,可以封装成一个组件,伪代码:
<div flex width=props.width height=props.height>
?<iframe flex:1>
?</iframe>
</div>
子应用的展示大小(空间)此时就由父应用中组件的props进行控制,我们的子应用最好设计成响应式的,以满足父应用中分配各种空间大小时,子应用的正常展示!