文章目录
iframe_1">iframe
iframe_2">一、iframe的优缺点
(一)优点
- 隔离性强
- 简单的嵌入方式
- 跨域资源嵌入方便
(二)缺点
- 性能开销
- SEO问题
- 布局和样式控制复杂
iframe_20">二、iframe基础应用
(一)基本语法
- 嵌入网页
- 使用
<iframe>
标签,通过src
属性指定要嵌入的网页地址。例如:
<iframe src="https://www.example.com"></iframe>
- 可以通过
width
和height
属性来控制iframe的尺寸。例如:
<iframe src="https://www.example.com" width="500px" height="300px"></iframe>
- 使用
- 设置边框和其他属性
frameborder
属性用于设置是否显示边框,0
表示不显示边框,1
表示显示边框。例如:
<iframe src="https://www.example.com" frameborder="0"></iframe>
- 还可以设置
scrolling
属性来控制是否显示滚动条,auto
(默认)表示根据内容自动显示滚动条,yes
表示始终显示滚动条,no
表示不显示滚动条。例如:
<iframe src="https://www.example.com" scrolling="no"></iframe>
(二)在实际场景中的应用
- 嵌入多媒体内容
- 可以嵌入视频或音频。例如,嵌入一个YouTube视频:
<iframe width="560" height="315" src="https://www.youtube.com/embed/VIDEO_ID" ></iframe>
- 其中
VIDEO_ID
是YouTube视频的唯一标识符。
- 嵌入外部工具或小部件
- 如嵌入一个在线表单工具。假设表单工具的网址是
https://form.example.com
,可以这样嵌入:
<iframe src="https://form.example.com" width="100%" height="500px"></iframe>
- 如嵌入一个在线表单工具。假设表单工具的网址是
iframe_56">三、iframe在无界微前端中的应用解析
(一)沙箱隔离
- 基于浏览器原生机制的隔离
- 样式隔离
- 安全隔离
(二)沙箱穿透
- 通信机制 - postMessage
- 在无界微前端中,虽然iframe提供了隔离,但有时微应用之间需要进行通信。这时可以使用
postMessage
API。主应用可以通过postMessage
向iframe中的微应用发送消息。例如,主应用有一个全局的用户登录状态变化,需要通知各个微应用。主应用可以这样发送消息:
javascript">const iframe = document.getElementById('microAppIframe'); iframe.contentWindow.postMessage({type: 'userLoggedIn', data: userData}, '*');
javascript">window.addEventListener('message', function(event) {if (event.data.type === 'userLoggedIn') {// 根据用户登录信息更新微应用状态updateMicroAppState(event.data.data);} });
- 在无界微前端中,虽然iframe提供了隔离,但有时微应用之间需要进行通信。这时可以使用
- 共享数据接口
- 可以通过定义共享的数据接口来实现沙箱穿透。例如,在主应用和微应用之间约定一个共享的存储对象,如
window.sharedData
。在安全可控的情况下,微应用可以通过这个共享对象来获取或修改一些全局相关的数据。不过这种方式需要谨慎处理,以确保数据的安全性和一致性,避免数据的滥用和冲突。
- 可以通过定义共享的数据接口来实现沙箱穿透。例如,在主应用和微应用之间约定一个共享的存储对象,如
四、无界微前端中 子应用全局弹窗应用方式
- 通信机制实现全局弹窗
- 使用postMessage进行通信
- 在无界微前端架构中,主应用和子应用通常是相互隔离的。当子应用需要弹出一个全局生效的窗口时,可以利用
postMessage
进行通信。子应用通过window.parent.postMessage
向主应用发送消息,告知主应用需要弹出窗口的相关信息,如窗口类型(是提示框、确认框还是自定义弹窗等)、窗口内容(文本信息、样式信息等)。 - 例如,子应用中有一个按钮点击事件触发弹窗,代码可以这样写:
javascript">document.getElementById('showPopupButton').addEventListener('click', function () {const popupData = {type: 'alert',message: '这是一个来自子应用的全局弹窗消息'};window.parent.postMessage(popupData, '*'); });
- 在无界微前端架构中,主应用和子应用通常是相互隔离的。当子应用需要弹出一个全局生效的窗口时,可以利用
- 主应用接收并处理消息
- 主应用需要监听
message
事件来接收子应用发送的消息。当接收到消息后,根据消息中的内容来创建和显示弹窗。如果是简单的alert
弹窗,主应用可以直接使用window.alert
函数。对于更复杂的自定义弹窗,可以通过操作主应用的DOM来创建和显示。 - 例如,主应用中的消息监听代码如下:
javascript">window.addEventListener('message', function (event) {if (event.data.type === 'alert') {window.alert(event.data.message);} else if (event.data.type === 'customPopup') {// 假设创建一个自定义弹窗的函数为createCustomPopupcreateCustomPopup(event.data);} });
- 主应用需要监听
- 使用postMessage进行通信
- 共享状态管理实现全局弹窗
- 使用全局状态管理库
- 可以引入像Redux、Mobx等全局状态管理库。在无界微前端架构中,主应用和子应用都可以访问和修改这个全局状态。当子应用需要弹出全局窗口时,它可以通过派发一个全局状态更新的动作。
- 例如,在使用Redux的情况下,子应用可以这样触发全局弹窗动作:
javascript">import { store } from '../mainApp/store'; document.getElementById('showPopupButton').addEventListener('click',function () {store.dispatch({type: 'SHOW_GLOBAL_POPUP',payload: {type: 'alert',message: '这是一个来自子应用的全局弹窗消息'}}); });
- 主应用根据状态变化显示弹窗
- 主应用中会有相应的Redux中间件或者监听器来处理状态变化。当收到
SHOW_GLOBAL_POPUP
这个动作时,主应用根据动作的payload
来创建和显示弹窗,就像在通信机制中处理消息一样,根据弹窗类型选择合适的显示方式。
- 主应用中会有相应的Redux中间件或者监听器来处理状态变化。当收到
- 使用全局状态管理库
- 事件总线实现全局弹窗
- 创建事件总线
- 在无界微前端架构中可以建立一个事件总线,它可以是一个简单的JavaScript对象,具有
on
(用于监听事件)、emit
(用于触发事件)等功能。主应用和子应用都可以访问这个事件总线。 - 例如,事件总线的简单实现如下:
javascript">const eventBus = {events: {},on: function (eventName, callback) {if (!this.events[eventName]) {this.events[eventName] = [];}this.events[eventName].push(callback);},emit: function (eventName, data) {if (this.events[eventName]) {this.events[eventName].forEach(callback => {callback(data);});}} };
- 在无界微前端架构中可以建立一个事件总线,它可以是一个简单的JavaScript对象,具有
- 子应用触发和主应用响应事件
- 子应用在需要弹出全局窗口时,通过事件总线的
emit
方法触发一个showGlobalPopup
事件,并传递弹窗相关的数据。主应用在初始化时通过事件总线的on
方法监听showGlobalPopup
事件,当事件被触发时,根据数据显示弹窗。 - 子应用中的触发代码:
javascript">import { eventBus } from '../common/eventBus'; document.getElementById('showPopupButton').addEventListener('click', function () {const popupData = {type: 'alert',message: '这是一个来自子应用的全局弹窗消息'};eventBus.emit('showGlobalPopup', popupData); });
- 主应用中的监听代码:
javascript">import { eventBus } from '../common/eventBus'; eventBus.on('showGlobalPopup', function (popupData) {if (popupData.type === 'alert') {window.alert(popupData.message);} else if (popupData.type === 'customPopup') {// 假设创建一个自定义弹窗的函数为createCustomPopupcreateCustomPopup(popupData);} });
- 子应用在需要弹出全局窗口时,通过事件总线的
- 创建事件总线
五、无界微前端中 全局状态管理
- 使用全局状态管理库(以Redux为例)
- 主应用中配置Redux
- 安装和创建store:在主应用中,首先安装Redux相关库(如
redux
和react - redux
,如果是基于React构建)。然后创建一个Redux store,这个store将用于存储全局状态。例如,创建一个简单的计数器状态:
javascript">import { createStore } from 'redux'; const initialState = {counter: 0 }; function reducer(state = initialState, action) {switch (action.type) {case 'INCREMENT':return {...state, counter: state.counter + 1 };case 'DECREMENT':return {...state, counter: state.counter - 1 };default:return state;} } const store = createStore(reducer);
- 将store挂载到全局对象(可选):为了方便子应用访问,可以将store挂载到
window
对象上,但这种方式可能会有一些潜在的安全风险和全局变量污染问题。更安全的做法是通过特定的接口来传递store。例如,在一个简单的场景下,可以这样挂载:
javascript">window.store = store;
- 安装和创建store:在主应用中,首先安装Redux相关库(如
- 子应用访问和修改状态
- 连接子应用到store:子应用可以通过导入主应用的store或者通过接口获取store来连接到全局状态。例如,在一个React子应用中,可以使用
react - redux
的connect
函数来连接组件到store。假设子应用中有一个组件需要显示和更新计数器的值:
javascript">import React from 'react'; import { connect } from 'react - redux'; function CounterComponent(props) {return (<div><p>Counter: {props.counter}</p><button onClick={() => props.increment()}>Increment</button><button onClick={() => props.decrement()}>Decrement</button></div>); } const mapStateToProps = state => ({counter: state.counter }); const mapDispatchToProps = dispatch => ({increment: () => dispatch({ type: 'INCREMENT' }),decrement: () => dispatch({ type: 'DECREMENT' }) }); export default connect(mapStateToProps, mapDispatchToProps) (CounterComponent);
- 连接子应用到store:子应用可以通过导入主应用的store或者通过接口获取store来连接到全局状态。例如,在一个React子应用中,可以使用
- 主应用中配置Redux
- 基于自定义事件实现全局状态管理
- 创建事件中心
- 在主应用中创建一个事件中心,用于管理状态变化事件。这个事件中心可以是一个简单的JavaScript对象,具有发布和订阅功能。例如:
javascript">const eventCenter = {events: {},subscribe: function (eventName, callback) {if (!this.events[eventName]) {this.events[eventName] = [];}this.events[eventName].push(callback);},publish: function (eventName, data) {if (this.events[eventName]) {this.events[eventName].forEach(callback => {callback(data);});}} };
- 管理全局状态
- 定义一些全局状态变量和操作这些变量的函数。例如,创建一个全局的用户登录状态变量和更新登录状态的函数:
javascript">let isUserLoggedIn = false; function updateLoginStatus(status) {isUserLoggedIn = status;eventCenter.publish('loginStatusChanged', isUserLoggedIn); }
- 子应用订阅和响应状态变化
- 子应用可以通过订阅事件中心的事件来获取全局状态的变化。例如,在一个子应用中,当用户登录状态改变时,更新界面显示:
javascript">eventCenter.subscribe('loginStatusChanged', function (isLoggedIn) {if (isLoggedIn) {// 显示用户相关界面} else {// 显示未登录界面} });
- 创建事件中心
- 利用iframe通信机制(如postMessage)实现全局状态共享
- 主应用状态管理和消息发送
- 主应用维护全局状态,当状态发生变化时,通过
postMessage
向所有子应用发送状态更新消息。例如,主应用中有一个主题切换状态,当主题改变时:
javascript">let currentTheme = 'light'; function changeTheme(newTheme) {currentTheme = newTheme;const allIframes = document.getElementsByTagName('iframe');for (let i = 0; i < allIframes.length; i++) {const iframe = allIframes[i];iframe.contentWindow.postMessage({type: 'themeChanged',theme: currentTheme}, '*');} }
- 主应用维护全局状态,当状态发生变化时,通过
- 子应用接收和更新状态
- 子应用在
window
对象上监听message
事件,接收主应用发送的状态更新消息,并更新自己的状态或界面。例如:
javascript">window.addEventListener('message', function (event) {if (event.data.type === 'themeChanged') {// 根据新主题更新子应用的样式或状态updateSubAppTheme(event.data.theme);} });
- 子应用在
- 主应用状态管理和消息发送
总结
iframe_304">一、iframe基础参数
(一)src属性
- 功能:用于指定要在iframe中显示的文档的URL(Uniform Resource Locator)。这是嵌入外部内容的关键参数。例如,
src="https://www.example.com"
会在iframe中加载该网址对应的网页内容。 - 应用场景:可以嵌入各种网页、在线文档、多媒体文件(如视频、音频等)。比如,在新闻网站嵌入外部新闻源,或者在企业官网嵌入第三方的产品介绍页面。
(二)width和height属性
- 功能:分别用于控制iframe的宽度和高度。可以使用像素(px)、百分比(%)等单位来设置尺寸。例如,
width="500px" height="300px"
将创建一个宽500像素、高300像素的iframe;width="80%" height="70%"
则会使iframe的宽度和高度分别占据父容器的80%和70%。 - 应用场景:根据页面布局和设计需求,精确调整iframe的大小,以适应不同的内容展示和屏幕尺寸。在响应式设计中,使用百分比单位可以让iframe随着父容器的大小变化而自适应。
(三)frameborder属性
- 功能:用于设置iframe边框的显示。
0
表示不显示边框,1
(或其他非零值)表示显示边框。例如,frameborder="0"
可以创建一个无边框的iframe,使嵌入的内容与页面其他部分在视觉上更加融合。 - 应用场景:在需要无缝嵌入内容,或者当页面整体风格要求简洁、无多余边框元素时,将
frameborder
设置为0
。而在需要明确区分嵌入内容和主页面时,可以显示边框。
(四)scrolling属性
- 功能:用于控制iframe是否显示滚动条。
auto
(默认值)表示根据iframe内部内容的高度和宽度自动决定是否显示滚动条;yes
表示始终显示滚动条;no
表示不显示滚动条。例如,scrolling="no"
可以隐藏滚动条,让内容在固定的iframe尺寸内显示,可能会导致部分内容无法看到。 - 应用场景:当嵌入的内容尺寸固定且已知可以完整显示在iframe内时,可设置
scrolling="no"
来保持页面简洁。若无法确定内容尺寸或者希望用户能方便地查看全部内容,则可以使用auto
。
(五)name属性
- 功能:为iframe指定一个名称,这个名称主要用于在表单提交或者通过JavaScript进行链接跳转时作为目标引用。例如,
name="myIframe"
,在一个表单中有一个提交按钮,设置target="myIframe"
时,表单提交后的结果将在该名称的iframe中显示。 - 应用场景:在涉及多个iframe和表单交互的复杂页面布局中,通过
name
属性可以精确控制表单提交后的内容显示位置,或者通过JavaScript代码中的window.open
等方法指定链接在特定名称的iframe中打开。
iframe_326">二、iframe应用技巧
(一)嵌入外部内容
- 跨域嵌入:iframe可以方便地嵌入来自其他域名的内容。在嵌入第三方内容(如社交媒体分享按钮、地图服务等)时,只需将其提供的嵌入代码(通常是包含iframe的HTML片段)复制到自己的页面中即可。例如,嵌入谷歌地图:
<iframe src="https://www.google.com/maps/embed?parameters"
width="600" height="450"></iframe>
- 嵌入多媒体:用于嵌入视频和音频内容。许多视频平台(如YouTube、Vimeo)提供了iframe嵌入代码,方便在其他网站展示视频。以YouTube为例,嵌入视频的基本代码格式如下:
<iframe width="560" height="315"
src="https://www.youtube.com/embed/VIDEO_ID"></iframe>
其中VIDEO_ID
是YouTube视频的唯一标识符。
(二)实现页面局部更新
- 独立加载内容:将页面中更新频繁或者加载速度较慢的部分放在iframe中,这样可以使这部分内容独立于主页面进行加载和更新。例如,在一个包含实时数据图表的网页中,将图表部分放在iframe中,当数据更新时,只需更新iframe中的内容,而不会影响主页面的其他部分。
- 异步加载技巧:可以通过JavaScript动态创建和加载iframe,实现异步加载内容。例如:
javascript">const iframe = document.createElement('iframe');
iframe.src = 'https://www.example.com';
iframe.width = '500px';
iframe.height = '300px';
document.body.appendChild(iframe);
这样可以在页面需要的时候(如用户点击某个按钮后)再加载iframe中的内容,提高页面初始加载速度。