构建 Web 代码编辑器
已发表: 2022-03-10当您没有机会使用代码编辑器应用程序时,或者当您想使用计算机甚至手机快速尝试 Web 上的某些内容时,在线 Web 代码编辑器最为有用。 这也是一个有趣的项目,因为了解如何构建代码编辑器将使您了解如何处理需要您集成代码编辑器以显示某些功能的其他项目。
为了在本文中继续学习,您需要了解以下几个 React 概念:
- 挂钩,
- 组件结构,
- 功能组件,
- 道具。
使用代码镜像
我们将使用一个名为 CodeMirror 的库来构建我们的编辑器。 CodeMirror 是一个用 JavaScript 为浏览器实现的通用文本编辑器。 它特别适用于编辑代码,并带有多种语言模式和附加组件,可实现更高级的编辑功能。
丰富的编程 API 和 CSS 主题系统可用于自定义 CodeMirror 以适应您的应用程序并使用新功能对其进行扩展。 它为我们提供了创建丰富的代码编辑器的功能,该编辑器可以在 Web 上运行并实时向我们显示代码的结果。
在下一节中,我们将设置新的 React 项目并安装构建 Web 应用程序所需的库。
创建一个新的 React 项目
让我们从创建一个新的 React 项目开始。 在命令行界面中,导航到要在其中创建项目的目录,让我们创建一个 React 应用程序并将其命名为code_editor
:
npx create-react-app code_editor
创建了新的 React 应用程序后,让我们在命令行界面中导航到该项目的目录:
cd code_editor
我们需要在这里安装两个库: codemirror
和react-codemirror2
。
npm install codemirror react-codemirror2
在安装了我们需要的这个项目的库之后,让我们创建我们的选项卡并启用将在我们的编辑器中显示的三个选项卡之间的选项卡切换(用于 HTML、CSS 和 JavaScript)。
按钮组件
让我们让按钮成为可重用的组件,而不是创建单独的按钮。 在我们的项目中,根据我们需要的三个选项卡,按钮将具有三个实例。
在src
文件夹中创建一个名为components
的文件夹。 在这个新的components
文件夹中,创建一个名为Button.jsx
的 JSX 文件。
以下是Button
组件所需的所有代码:
import React from 'react' const Button = ({title, onClick}) => { return ( <div> <button style={{ maxWidth: "140px", minWidth: "80px", height: "30px", marginRight: "5px" }} onClick={onClick} > {title} </button> </div> ) } export default Button
以下是我们上面所做的完整解释:
- 我们创建了一个名为
Button
的功能组件,然后将其导出。 - 我们从进入组件的 props 中解构了
title
和onClick
。 在这里,title
将是一个文本字符串,onClick
将是一个在单击按钮时调用的函数。 - 接下来,我们使用
button
元素来声明我们的按钮,并使用style
属性来设置按钮的样式,使其看起来像样。 - 我们添加了
onClick
属性并将我们解构的onClick
函数道具传递给它。 - 您会注意到我们在此组件中所做的最后一件事是将
{title}
作为button
标签的内容传递。 这允许我们根据调用时传递给按钮组件实例的道具动态显示标题。
现在我们已经创建了一个可重用的按钮组件,让我们继续并将我们的组件引入App.js.
转到App.js
并导入新创建的按钮组件:
import Button from './components/Button';
要跟踪打开的选项卡或编辑器,我们需要一个声明状态来保存打开的编辑器的值。 使用useState
React 钩子,我们将设置状态,该状态将存储单击该选项卡按钮时当前打开的编辑器选项卡的名称。
以下是我们的做法:
import React, { useState } from 'react'; import './App.css'; import Button from './components/Button'; function App() { const [openedEditor, setOpenedEditor] = useState('html'); return ( <div className="App"> </div> ); } export default App;
在这里,我们声明了我们的状态。 它采用当前打开的编辑器的名称。 因为值html
作为状态的默认值传递,所以 HTML 编辑器将默认打开选项卡。
让我们继续编写函数,该函数将使用setOpenedEditor
来更改单击选项卡按钮时的状态值。
注意:两个选项卡可能不会同时打开,所以我们在编写函数时必须考虑到这一点。
这是我们名为onTabClick
的函数的样子:
import React, { useState } from 'react'; import './App.css'; import Button from './components/Button'; function App() { ... const onTabClick = (editorName) => { setOpenedEditor(editorName); }; return ( <div className="App"> </div> ); } export default App;
在这里,我们传递了一个函数参数,它是当前选择的选项卡的名称。 该参数将在调用函数的任何位置提供,并且将传入该选项卡的相关名称。
让我们为我们需要的三个选项卡创建Button
的三个实例:
<div className="App"> <p>Welcome to the editor!</p> <div className="tab-button-container"> <Button title="HTML" onClick={() => { onTabClick('html') }} /> <Button title="CSS" onClick={() => { onTabClick('css') }} /> <Button title="JavaScript" onClick={() => { onTabClick('js') }} /> </div> </div>
这是我们所做的:
- 我们首先添加了一个
p
标签,基本上只是为了给我们的应用程序的内容提供一些上下文。 - 我们使用
div
标签来包装我们的标签按钮。div
标签带有一个className
,我们将在本教程后面的 CSS 文件中使用它来将按钮设置为网格显示。 - 接下来,我们声明了
Button
组件的三个实例。 如果你还记得,Button
组件有两个 props,title
和onClick
。 在Button
组件的每个实例中,都提供了这两个道具。 -
title
属性采用选项卡的标题。 -
onClick
属性接受一个我们刚刚创建的函数onTabClick
,它接受一个参数:所选选项卡的名称。
根据当前选择的选项卡,我们将使用 JavaScript 三元运算符有条件地显示选项卡。 这意味着如果openedEditor
状态的值设置为html
(即setOpenedEditor('html')
),那么HTML 部分的选项卡将成为当前可见的选项卡。 当我们在下面这样做时,您会更好地理解这一点:
... return ( <div className="App"> ... <div className="editor-container"> { openedEditor === 'html' ? ( <p>The html editor is open</p> ) : openedEditor === 'css' ? ( <p>The CSS editor is open!!!!!!</p> ) : ( <p>the JavaScript editor is open</p> ) } </div> </div> ); ...
让我们用简单的英语回顾一下上面的代码。 如果openedEditor
的值为html
,则显示 HTML 部分。 否则,如果openedEditor
的值为css
,则显示 CSS 部分。 否则,如果该值既不是html
也不是css
,那么这意味着该值必须是js
,因为openedEditor
状态只有三个可能的值; 所以,然后我们将显示 JavaScript 的选项卡。
我们对三元运算符条件中的不同部分使用了段落标签 ( p
)。 随着我们继续,我们将创建编辑器组件并用编辑器组件本身替换p
标签。
我们已经走到这一步了! 单击按钮时,它会触发将其代表的选项卡设置为true
的操作,从而使该选项卡可见。 这是我们的应用程序当前的样子:
让我们在包含按钮的div
容器中添加一点 CSS。 我们希望按钮显示在网格中,而不是像上图那样垂直堆叠。 转到您的App.css
文件并添加以下代码:
.tab-button-container{ display: flex; }
回想一下,我们添加了className="tab-button-container"
作为包含三个选项卡按钮的div
标记中的属性。 在这里,我们为该容器设置样式,使用 CSS 将其显示设置为flex
。 这是结果:
为你为达到这一点所做的努力感到自豪。 在下一节中,我们将创建我们的编辑器,用它们替换p
标签。
创建编辑器
因为我们已经在 CodeMirror 编辑器中安装了要处理的库,所以让我们继续在components
文件夹中创建Editor.jsx
文件。
组件 > Editor.jsx
创建新文件后,让我们在其中编写一些初始代码:
import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { return ( <div className="editor-container"> </div> ) } export default Editor
这是我们所做的:
- 我们将 React 与
useState
挂钩一起导入,因为我们将需要它。 - 我们导入了 CodeMirror CSS 文件(它来自我们安装的 CodeMirror 库,因此您不必以任何特殊方式安装它)。
- 我们从
react-codemirror2
导入Controlled
,将其重命名为ControlledEditorComponent
以使其更清晰。 我们将很快使用它。 - 然后,我们声明了我们的
Editor
功能组件,我们有一个带有空div
的 return 语句,现在在 return 语句中有一个className
。
在我们的函数组件中,我们从 props 中解构了一些值,包括language
、 value
和setEditorState
。 当在App.js
中调用编辑器时,这三个道具将在编辑器的任何实例中提供。
让我们使用ControlledEditorComponent
为我们的编辑器编写代码。 这是我们要做的:
import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/css/css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { return ( <div className="editor-container"> <ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, }} /> </div> ) } export default Editor
让我们来看看我们在这里做了什么,解释一些 CodeMirror 术语。
CodeMirror 模式指定编辑器适用于哪种语言。 我们导入了三种模式,因为我们有这个项目的三个编辑器:
- XML:此模式适用于 HTML。 它使用术语 XML。
- JavaScript:这(
codemirror/mode/javascript/javascript
)引入了 JavaScript 模式。 - CSS:这(
codemirror/mode/css/css
)引入了 CSS 模式。
注意:因为编辑器是作为可重用的组件构建的,所以我们不能在编辑器中放置直接模式。 所以,我们通过我们解构的language
道具来提供模式。 但这并没有改变需要导入模式才能工作的事实。
接下来,我们来讨论一下ControlledEditorComponent
中的东西:
-
onBeforeChange
每当您向编辑器写入或从编辑器中删除时,都会调用此方法。 可以将其想象为通常在输入字段中用于跟踪更改的onChange
处理程序。 使用它,我们将能够在有新更改的任何时候获取编辑器的值并将其保存到编辑器的状态。 我们将继续编写{handleChange}
函数。 -
value = {value}
这只是编辑器在任何给定时间的内容。 我们将一个名为value
的解构道具传递给该属性。value
props 是保存该编辑器值的状态。 这将由编辑器的实例提供。 -
className
="code-mirror-wrapper"
这个类名不是我们自己制作的样式。 它由我们在上面导入的 CodeMirror 的 CSS 文件提供。 -
options
这是一个具有我们希望编辑器具有的不同功能的对象。 CodeMirror 中有许多令人惊叹的选项。 让我们看看我们在这里使用的那些:-
lineWrapping: true
这意味着当行满时代码应该换行到下一行。 -
lint: true
这允许掉毛。 -
mode: language
如上所述,此模式采用编辑器将要使用的语言。 上面已经导入了语言,但是编辑器将根据通过 prop 提供给编辑器的language
值应用一种语言。 -
lineNumbers: true
这指定编辑器应该有每一行的行号。
-
接下来,我们可以为onBeforeChange
处理程序编写handleChange
函数:
const handleChange = (editor, data, value) => { setEditorState(value); }
onBeforeChange
处理程序让我们可以访问三件事: editor, data, value
。
我们只需要这个value
,因为它是我们想要在setEditorState
中传递的值。 setEditorState
属性代表我们在App.js
中声明的每个状态的设置值,保存每个编辑器的值。 随着我们继续,我们将看看如何将其作为道具传递给Editor
组件。
接下来,我们将添加一个下拉列表,允许我们为编辑器选择不同的主题。 那么,让我们看看 CodeMirror 中的主题。
CodeMirror 主题
CodeMirror 有多个主题可供我们选择。 访问官方网站以查看可用的不同主题的演示。 让我们创建一个包含不同主题的下拉列表,用户可以在我们的编辑器中选择这些主题。 在本教程中,我们将添加五个主题,但您可以添加任意数量的主题。
首先,让我们在Editor.js
组件中导入我们的主题:
import 'codemirror/theme/dracula.css'; import 'codemirror/theme/material.css'; import 'codemirror/theme/mdn-like.css'; import 'codemirror/theme/the-matrix.css'; import 'codemirror/theme/night.css';
接下来,创建一个包含我们导入的所有主题的数组:
const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night']
让我们声明一个useState
挂钩来保存所选主题的值,并将默认主题设置为dracula
:
const [theme, setTheme] = useState("dracula")
让我们创建下拉列表:
... return ( <div className="editor-container"> <div style={{marginBottom: "10px"}}> <label for="cars">Choose a theme: </label> <select name="theme" onChange={(el) => { setTheme(el.target.value) }}> { themeArray.map( theme => ( <option value={theme}>{theme}</option> )) } </select> </div> // the rest of the code comes below... </div> ) ...
在上面的代码中,我们使用label
HTML 标签向我们的下拉列表添加标签,然后添加select
HTML 标签来创建我们的下拉列表。 select
元素中的option
标签定义下拉菜单中可用的选项。
因为我们需要用我们创建的themeArray
中的主题名称填充下拉列表,所以我们使用.map
数组方法来映射themeArray
并使用option
标签单独显示名称。
等等——我们还没有解释完上面的代码。 在开始的select
标签中,我们传递了onChange
属性来跟踪和更新theme
状态,只要在下拉列表中选择了新值。 每当在下拉列表中选择一个新选项时,该值都是从返回给我们的对象中获取的。 接下来,我们使用 state hook 中的setTheme
将新值设置为 state 持有的值。
至此,我们已经创建了下拉列表,设置了主题的状态,并编写了我们的函数来设置具有新值的状态。 为了使 CodeMirror 使用我们的主题,我们需要做的最后一件事是将主题传递给ControlledEditorComponent
中的options
对象。 在options
对象中,我们添加一个名为theme
的值,并将其值设置为所选主题的状态值,也名为theme
。
这是ControlledEditorComponent
现在的样子:
<ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, theme: theme, }} />
现在,我们制作了一个可以在编辑器中选择的不同主题的下拉列表。
以下是Editor.js
中的完整代码目前的样子:
import React, { useState } from 'react'; import 'codemirror/lib/codemirror.css'; import 'codemirror/theme/dracula.css'; import 'codemirror/theme/material.css'; import 'codemirror/theme/mdn-like.css'; import 'codemirror/theme/the-matrix.css'; import 'codemirror/theme/night.css'; import 'codemirror/mode/xml/xml'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/css/css'; import { Controlled as ControlledEditorComponent } from 'react-codemirror2'; const Editor = ({ language, value, setEditorState }) => { const [theme, setTheme] = useState("dracula") const handleChange = (editor, data, value) => { setEditorState(value); } const themeArray = ['dracula', 'material', 'mdn-like', 'the-matrix', 'night'] return ( <div className="editor-container"> <div style={{marginBottom: "10px"}}> <label for="themes">Choose a theme: </label> <select name="theme" onChange={(el) => { setTheme(el.target.value) }}> { themeArray.map( theme => ( <option value={theme}>{theme}</option> )) } </select> </div> <ControlledEditorComponent onBeforeChange={handleChange} value= {value} className="code-mirror-wrapper" options={{ lineWrapping: true, lint: true, mode: language, lineNumbers: true, theme: theme, }} /> </div> ) } export default Editor
我们只需要设置一个className
样式。 转到App.css
并添加以下样式:
.editor-container{ padding-top: 0.4%; }
现在我们的编辑器已经准备好了,让我们回到App.js
并在那里使用它们。
src > App.js
我们需要做的第一件事是在此处导入Editor.js
组件:
import Editor from './components/Editor';
在App.js
中,让我们分别声明将保存 HTML、CSS 和 JavaScript 编辑器内容的状态。
const [html, setHtml] = useState(''); const [css, setCss] = useState(''); const [js, setJs] = useState('');
如果您还记得,我们将需要使用这些状态来保存和提供我们编辑器的内容。
接下来,让我们用刚刚创建的编辑器组件替换我们在条件渲染中用于 HTML、CSS 和 JavaScript 的段落 ( p
) 标签,我们还将向编辑器的每个实例传递适当的 prop零件:
function App() { ... return ( <div className="App"> <p>Welcome to the edior</p> // This is where the tab buttons container is... <div className="editor-container"> { htmlEditorIsOpen ? ( <Editor language="xml" value={html} setEditorState={setHtml} /> ) : cssEditorIsOpen ? ( <Editor language="css" value={css} setEditorState={setCss} /> ) : ( <Editor language="javascript" value={js} setEditorState={setJs} /> ) } </div> </div> ); } export default App;
如果你一直跟着到现在,你就会明白我们在上面的代码块中做了什么。
这里是简单的英语:我们用编辑器组件的实例替换了p
标签(作为占位符)。 然后,我们分别提供它们的language
、 value
和setEditorState
来匹配它们对应的状态。
我们已经走了这么远! 这是我们的应用程序现在的样子:
iframe 简介
我们将使用内联框架 (iframe) 来显示在编辑器中输入的代码的结果。
根据 MDN:
HTML 内联框架元素 (
<iframe>
) 表示嵌套的浏览上下文,将另一个 HTML 页面嵌入到当前页面中。
iframe 如何在 React 中工作
iframe 通常与纯 HTML 一起使用。 将 iframe 与 React 一起使用不需要很多更改,主要是将属性名称转换为驼峰式。 一个例子是srcdoc
会变成srcDoc
。
Web 上 iframe 的未来
iframe 在 Web 开发中仍然非常有用。 您可能想要检查的是门户。 正如 Daniel Brain 解释的那样:
“门户网站在这种组合中引入了一组强大的新功能。 现在可以构建一些感觉像 iframe 的东西,它可以无缝地动画和变形,并接管整个浏览器窗口。”
Portals 试图解决的问题之一是 URL 栏问题。 使用 iframe 时,在 iframe 中渲染的组件不会在地址栏中携带唯一的 URL; 因此,这可能对用户体验不利,具体取决于用例。 Portals 值得一试,我建议您这样做,但因为它不是我们文章的重点,所以我将在此仅介绍它。
创建 iframe 来存放我们的结果
让我们继续我们的教程,创建一个 iframe 来容纳我们的编辑器的结果。
return ( <div className="App"> // ... <div> <iframe srcDoc={srcDoc} title="output" sandbox="allow-scripts" frameBorder="1" width="100%" height="100%" /> </div> </div> );
在这里,我们创建了 iframe 并将其存放在div
容器标签中。 在 iframe 中,我们传递了一些我们需要的属性:
-
srcDoc
srcDoc
属性是用驼峰写的,因为这是在 React 中编写 iframe 属性的方法。 使用 iframe 时,我们可以在页面上嵌入外部网页或呈现指定的 HTML 内容。 要加载和嵌入外部页面,我们将使用src
属性。 在我们的例子中,我们没有加载外部页面; 相反,我们想创建一个新的内部 HTML 文档来存放我们的结果; 为此,我们需要srcDoc
属性。 该属性采用我们想要嵌入的 HTML 文档(我们还没有创建它,但很快就会创建)。 -
title
title 属性用于描述内联框架的内容。 -
sandbox
这个属性有很多用途。 在我们的例子中,我们使用它来允许脚本在我们的 iframe 中使用allow-scripts
值运行。 因为我们正在使用 JavaScript 编辑器,所以这会很快派上用场。 -
frameBorder
这仅定义了 iframe 的边框厚度。 -
width
和height
这定义了 iframe 的宽度和高度。
这些术语现在应该对您更有意义。 让我们继续并声明将保存srcDoc
的 HTML 模板文档的状态。 如果您仔细查看上面的代码块,您会看到我们向srcDoc
属性传递了一个值: srcDoc
={srcDoc}
。 让我们使用我们的useState()
React 钩子来声明srcDoc
状态。 为此,在App.js
文件中,转到我们定义其他状态的位置并添加以下状态:
const [srcDoc, setSrcDoc] = useState(` `);
现在我们已经创建了状态,接下来要做的就是在我们在代码编辑器中输入时在状态中显示结果。 但是我们不希望在每次按键时重新渲染组件。 考虑到这一点,让我们继续。
配置 iframe 以显示结果
每次分别在 HTML、CSS 和 JavaScript 的任何编辑器中发生更改时,我们都希望触发useEffect()
,这将在 iframe 中呈现更新的结果。 让我们在App.js
文件中编写useEffect()
来执行此操作:
首先,导入useEffect()
钩子:
import React, { useState, useEffect } from 'react';
让我们这样写useEffect()
:
useEffect(() => { const timeOut = setTimeout(() => { setSrcDoc( ` <html> <body>${html}</body> <style>${css}</style> <script>${js}</script> </html> ` ) }, 250); return () => clearTimeout(timeOut) }, [html, css, js])
在这里,我们编写了一个useEffect()
挂钩,只要我们为 HTML、CSS 和 JavaScript 编辑器声明的值状态发生更改或更新,该挂钩就会始终运行。
为什么我们需要使用setTimeout()
? 好吧,如果我们在没有它的情况下编写它,那么每次在编辑器中按下一个键,我们的 iframe 都会更新,这通常不利于性能。 所以我们使用setTimeout()
将更新延迟 250 毫秒,让我们有足够的时间知道用户是否还在打字。 也就是说,每次用户按下一个键时,它都会重新开始计数,因此 iframe 只会在用户空闲(未键入)250 毫秒时更新。 这是避免每次按下键时都必须更新 iframe 的一种很酷的方法。
我们在上面做的下一件事是用新的变化来更新srcDoc
。 如上所述, srcDoc
组件在 iframe 中呈现指定的 HTML 内容。 在我们的代码中,我们传递了一个 HTML 模板,获取包含用户在 HTML 编辑器中键入的代码的html
状态,并将其放置在模板的body
标记之间。 我们还获取了包含用户在 CSS 编辑器中键入的样式的css
状态,并在style
标签之间传递了它。 最后,我们获取包含用户在 JavaScript 编辑器中键入的 JavaScript 代码的js
状态,并在script
标签之间传递它。
请注意,在设置setSrcDoc
时,我们使用了反引号 ( ` `
) 而不是普通引号 ( ' '
)。 这是因为反引号允许我们传入相应的状态值,就像我们在上面的代码中所做的那样。
useEffect()
钩子中的return
语句是一个清理函数,它在完成时清除setTimeout()
,以避免内存泄漏。 该文档有更多关于useEffect
的信息。
这是我们的项目目前的样子:
CodeMirror 插件
使用 CodeMirror 插件,我们可以使用其他代码编辑器中的更多功能来增强我们的编辑器。 让我们来看一个在输入开始标签时自动添加结束标签的示例,以及在输入开始括号时自动结束括号的另一个示例:
首先要做的是将插件导入到我们的App.js
文件中:
import 'codemirror/addon/edit/closetag'; import 'codemirror/addon/edit/closebrackets';
让我们在ControlledEditorComponent
选项中传递它:
<ControlledEditorComponent ... options={{ ... autoCloseTags: true, autoCloseBrackets: true, }} />
现在这就是我们所拥有的:
您可以将大量这些插件添加到您的编辑器中,以使其具有更丰富的功能。 我们不可能在这里遍历所有这些。
现在我们已经完成了这些,让我们简要讨论一下我们可以做些什么来提高我们的应用程序的可访问性和性能。
解决方案的性能和可访问性
看看我们的网络代码编辑器,有些东西肯定可以改进。
因为我们主要关注功能,所以我们可能会稍微忽略设计。 为了获得更好的可访问性,您可以采取以下措施来改进此解决方案:
- 您可以在当前打开的编辑器的按钮上设置一个
active
类。 突出显示该按钮将通过让用户清楚地指示他们当前正在使用哪个编辑器来提高可访问性。 - 您可能希望编辑器占用比我们这里更多的屏幕空间。 您可以尝试的另一件事是通过单击停靠在侧面某处的按钮来弹出 iframe。 这样做会给编辑器更多的屏幕空间。
- 这种编辑器对于想要在移动设备上进行快速练习的人很有用,因此需要完全适应移动设备(更不用说上面关于移动设备的两点了)。
- 目前,我们可以在加载的多个主题中切换编辑器组件的主题,但页面的总体主题保持不变。 您可以让用户在整个布局的深色和浅色主题之间切换。 这将有利于可访问性,减轻人们长时间看明亮的屏幕对眼睛的压力。
- 我们没有考虑 iframe 的安全问题,主要是因为我们在 iframe 中加载了内部 HTML 文档,而不是外部文档。 所以我们不需要考虑太仔细,因为 iframe 非常适合我们的用例。
- 对于 iframe,另一个考虑因素是页面加载时间,因为 iframe 中加载的内容通常不受您的控制。 在我们的应用程序中,这不是问题,因为我们的 iframe 内容不是外部的。
当您构建任何应用程序时,性能和可访问性都值得考虑很多,因为它们将决定您的应用程序对其用户的有用性和可用性。
Shedrack 在解释改进和优化 React 应用程序性能的方法方面做得很好。 值得一试!
结论
通过不同的项目工作有助于我们了解广泛的主题。 既然您已经阅读了这篇文章,请随意扩展您的体验,尝试更多的插件以使代码编辑器更丰富,改进 UI,并修复上面概述的可访问性和性能问题。
- 该项目的整个代码库可在 GitHub 上找到。
这是 Codesandbox 上的演示:
链接和材料
- “谷歌浏览器的门户:像 iframe,但更好,更差”,Daniel Brain
- “优化性能”,React 文档
- “用户手册和参考指南”,CodeMirror 文档