在构建网页时,开发人员经常需要包括来自其他网页的资源。你在浏览网页时可能会认识到一些常见的例子,包括Twitter的分享按钮,Facebook的喜欢按钮,以及谷歌地图的地图显示。
检索这类数据的一个流行方式是使用iframe。iframe是inline frame的缩写,本质上是一个框架中的框架。使用<iframe/>
标签,你可以很容易地将来自其他来源的外部内容直接嵌入到你的网页中。开发人员还使用iframe将某些资源从同一网页中隔离出来,例如,通过渲染将组件封装在iframe中。
在本教程中,我们将通过观察这两种不同的用例来探索React中的iframes。首先,让我们介绍一些背景信息,说明iframes如何工作以及我们应该如何使用它们。让我们开始吧!
在React中使用iframes的最佳实践
当一个资源在iframe中被渲染时,它的功能独立于嵌入它的父组件。因此,父组件的CSS样式和它的JavaScript都不会对iframe产生任何影响。
在React中,开发者使用iframe来创建一个沙盒组件或一个与父组件隔离的应用程序。在iframe中,当一段内容从外部源嵌入时,它完全由源控制,而不是由它所嵌入的网站控制。
出于这个原因,重要的是只嵌入来自可信来源的内容。请记住,iframes也会占用额外的内存。如果内容太重,会减慢你的网页加载时间,所以你应该谨慎使用iframes。
嵌入外部来源的网页
首先,我们将学习如何从外部来源嵌入网页,这可能是iframes更常见的使用情况。现在,你很少看到一个没有从外部来源加载任何内容的网络应用。
例如,考虑一下你在网页上发现了多少YouTube视频,你在应用之外看到的Instagram帖子,博客上的Facebook评论区,甚至是网页上的广告。这些元素中的每一个都被嵌入到网站中,其复杂程度可以从一行代码到整个代码部分。
我们可以使用下面这行代码,在React应用中添加一个Twitter Tweet按钮。
<iframe src="https://platform.twitter.com/widgets/tweet_button.html"></iframe>
我们将在下面的代码中使用上面的代码片段,生成一个像下面截图中的Tweet按钮。当用户点击Tweet按钮时,所选内容将在他们的Twitter主页上以新的Tweet方式打开。
function App() {
return (
<div className="App">
<h3>Iframes in React</h3>
<iframe src="https://platform.twitter.com/widgets/tweet_button.html"></iframe>
</div>
);
}
export default App;
iframe标签属性
现在,让我们回顾一下iframe标签的一些有用的属性,这将允许你修改和定制你的iframe。其一,src
,用于设置你要嵌入的网页的地址。例如,我们可以使用src
标签来嵌入一个YouTube视频,如下所示。
<iframe src="https://www.youtube.com/embed/uXWycyeTeCs" ></iframe>
srcdoc
是用来设置一个内联的HTML来嵌入。请注意,如果srcdoc
属性同时存在,它将覆盖src
属性。在下面的代码片断中,我们将用srcdoc
命令覆盖Youtube视频的src
命令,该命令是用一个hello消息作为占位符。
<iframe src="https://www.youtube.com/embed/uXWycyeTeCs" srcDoc='<p>Hello from Iframe</p>' ></iframe>
我们将使用height
和width
属性来设置我们iframe的高度和宽度。默认单位是像素,但是,你也可以使用其他单位。在下面的代码片段中,我们将设置一个显示YouTube视频的iframe的尺寸,见以下截图。
<iframe src="https://www.youtube.com/embed/uXWycyeTeCs" width={1000} height={500} ></iframe>
allow
属性根据请求的来源来设置<iframe>
的可用功能,例如,访问自动播放、麦克风等。在下面的截图中,我们为我们的YouTube视频设置了allow
,数值如下:accelerometer
,autoplay
,clipboard-write
,encrypted-media
,gyroscope
, 和picture-in-picture full
。
<iframe src="https://www.youtube.com/embed/uXWycyeTeCs" width={1000} height={500} allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture full"></iframe>
title
属性用于为iframe中的内容设置一个描述。虽然title
属性对iframe的用户界面没有影响,但它对可访问性很有帮助,为屏幕阅读器提供有价值的输入。在下面的代码片断中,我们正在向我们的YouTube视频添加一个title
。
<iframe src="https://www.youtube.com/embed/uXWycyeTeCs" width={1000} height={500} title='A youtube video on React hooks'></iframe>
接下来,我们使用name
属性来设置iframe的名称,并在JavaScript中引用该元素。
为了对iframe的内容设置限制,我们使用Sandbox
。正如本教程前面提到的,我们不能控制从外部来源发送的内容,但是,我们可以使用Sandbox
来限制我们在iframe中接受的内容。要应用所有的限制,让属性的值为空。或者,你可以添加标志来放松限制。
例如,allow-modals
将允许外部页面打开模版,而allow-scripts
允许资源运行脚本。
<iframe src="https://www.youtube.com/embed/uXWycyeTeCs" width={1000} height={500} sandbox='allow-scripts allow-modal' ></iframe>
正确使用Sandbox
属性及其标志,可以大大改善你的应用程序的安全性,特别是当你嵌入的资源来自恶意来源时。
为了设置浏览器应如何加载iframe内容,我们将使用loading
属性;loading
需要eager
或lazy
。当设置为eager
,iframe会被立即加载,即使它在可见视口之外,这是默认值。lazy
会延迟加载,直到它与视口达到一个计算的距离,由浏览器定义。
<iframe src="https://www.youtube.com/embed/uXWycyeTeCs" width={1000} height={500} sandbox='allow-scripts allow-modal' loading='eager'></iframe>
在iframe中渲染一个React应用或组件
当你不需要控制在iframe中渲染的内容时,我们刚才介绍的方法是一个很好的策略。如果你想向你的页面访问者展示YouTube上的视频或Instagram上的帖子,你可以简单地在src
属性中添加URL。
但是,如果你正在构建一个复杂的应用程序,例如,一个允许用户在同一平台上构建独立应用程序的CodeSandbox,或者一个在用户点击按钮时被触发的聊天机器人,该怎么办?在这两个例子中,你都控制着内容,但你也想把它们与应用的其他部分隔离开来。
在本节中,我们将探讨在iframe中渲染React应用或组件。当你想削减CSS的多余部分或在另一个应用中使用一个完整的应用而不受到任何干扰时,这是一个很好的策略,特别是当你想让iframe的内容与它的父级共享状态时。
让我们尝试把我们的iframe渲染成iframe的直接子节点。
function App() {
return (
<div className='App'>
<p>Iframes in React</p>
<iframe >
<MyComponent />
</iframe>
</div>
);
}
export default App;
然而,当我们运行上面的代码时,我们什么都没有得到。
你只能使用src
属性来设置我们要渲染的URL。因为我们要在同一个应用程序中渲染一个组件,所以src
属性就不起作用了。
另外,我们可以使用srcdoc
属性,它接收一个内联的HTML来嵌入。然而,我们就会试图渲染整个应用程序或组件,并使用大量冗长的代码。我们需要找到一种方法来渲染iframe主体中的组件,而不是作为它的一个孩子。为此,我们将使用一个门户。
React门户
根据React文档,门户允许我们将子节点渲染到存在于父组件DOM层次结构之外的DOM节点中。基本上,门户让我们在任何我们想去的地方渲染儿童。
你可以用下面的命令创建一个门户。
ReactDOM.createPortal(child, container)
在这种情况下,孩子是一个React元素、片段或字符串,而容器是DOM位置或节点,门户应该被渲染到那里。
有了React门户,我们可以选择在DOM层次结构中放置一个DOM节点的位置。要做到这一点,我们首先要建立一个对现有的和已安装的DOM节点的引用。在这种情况下,它将在一个给定的<iframe>
的contentWindow
。然后,我们将用它创建一个门户。门户的内容也被认为是父方虚拟DOM的孩子。
假设我们有下面这个文件,叫做MyComponent.js
。
import React from 'react'
function MyComponent() {
return (
<div>
<p style={{color: 'red'}}>Testing to see if my component renders!</p>
</div>
)
}
export default MyComponent;
现在,让我们创建一个名为CustomIframe.js
的文件,并编写以下代码。
import React, { useState } from 'react'
import { createPortal } from 'react-dom'
const CustomIframe = ({
children,
...props
}) => {
const [contentRef, setContentRef] = useState(null)
const mountNode =
contentRef?.contentWindow?.document?.body
return (
<iframe {...props} ref={setContentRef}>
{mountNode && createPortal(children, mountNode)}
</iframe>
)
}
export default CustomIframe;
我们用useState()
Hook创建了一个ref
,因此,一旦状态被更新,该组件将重新渲染。我们还获得了对iframe文档主体的访问权,然后创建了一个门户,代替其主体渲染传递给iframe
的孩子。
import './App.css';
import CustomIframe from './CustomIframe';
import MyComponent from './MyComponent';
function App() {
return (
<CustomIframe title='A custom made iframe'>
<MyComponent />
</CustomIframe>
);
}
export default App;
你可以把任何React应用或组件作为CustomIframe
的子节点传递,它就可以正常工作了!
React应用程序或组件将成为封装的,这意味着你可以独立开发和维护它。
你也可以通过使用一个叫做react frame component
的库来实现上述相同的封装。要安装它,请运行以下命令。
npm install --save react-frame-component
对你的组件进行如下封装。
import Frame from 'react-frame-component';
function App() {
return (
<div className='App'>
<p>Iframes in React</p>
<Frame >
<MyComponent />
</Frame>
</div>
);
}
export default App;
结论
在本教程中,我们在两个不同的用例中探索了React中的iframes。首先,我们学习了如何用iframe将网页中的外部内容嵌入到Web应用中,将父元素和子元素的JavaScript和CSS分开。其次,我们学习了如何在iframe中隔离我们应用程序的某些部分。
iframe是一个有用的元素,对开发者来说是必须要学习的。我希望你喜欢这个教程!
The postBest practices for React iframesappeared first onLogRocket Blog.