从头开始构建一个React代码编辑器和语法高亮器

1,367 阅读9分钟

开发人员用记事本编码,博客只用HTML显示代码块的日子已经一去不复返了。突出显示的代码更赏心悦目,也更容易阅读。

在本教程中,我们将创建一个React代码编辑器和语法高亮器,这样你就可以输入你的代码并看到它是如何被高亮显示的。我们还将在编辑器中提供互动性,这意味着用户将能够在多种语言和主题之间切换。

源代码将在这里提供,供参考。

React代码编辑器和语法高亮器的线框设计

首先,让我们创建一个简单的线框来设计组件的布局。

Wireframe

整个应用程序将驻留在App ,它将是我们应用程序的主要封装器。

App 内,将有ControlsBoxPanelsBox 组件。

ControlsBox 我们还将包括两个 组件。一个用于选择输入语言,另一个用于选择突出显示的主题。Dropdown

设置React代码编辑器项目

为了创建一个项目模板,我们将使用Create React App,它将在一分钟或更短的时间内设置一个完全配置的React项目。

要做到这一点,打开你的终端并运行以下命令。

npx create-react-app syntax-highlighter

然后通过运行cd syntax-highlighter ,切换到新创建的文件夹,通过运行npm start ,启动React开发服务器。

这应该会自动打开你的浏览器。你应该看到一个React默认的应用程序在端口3000

打开src 文件夹,删除所有文件,除了App.js,App.css,index.js, 和index.css 。然后删除每个文件中的内容,因为我们将完全从头开始重写每个文件。

创建基础

首先,我们将创建我们项目的基础结构。

让我们从index.js 开始,它将渲染我们的应用程序。打开它并包含以下代码。

javascript
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

为了渲染,我们首先导入了ReactDOM 组件。然后,我们导入了一个扩展的样式表,来为基座设计样式。最后,我们导入了App 组件,并对它进行了设置,使它在DOM树内的root 元素中被渲染。

现在,打开index.css 文件并包含以下样式。

css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  width: 100vw;
  min-height: 100vh;
  font-family: sans-serif;
  background-color: #ffdee9;
  background-image: linear-gradient(0deg, #ffdee9 0%, #b5fffc 100%);
}

我们首先为margin,padding, 和box-sizing 创建了重置规则,所以我们不必担心以后这些浏览器的默认值问题。这是很常见的做法,建议你在任何项目中从头开始建立。

我们还为body 创建了特定的规则,以便它总是充满整个屏幕的视口。我们还设置了一个特定的字体家族和一个渐变的背景。

打开App.js ,我们的应用程序的所有逻辑都在这里。包括以下代码。

javascript
import "./App.css";

export default function App() {
  return (
    <div className="App">
      <div className="ControlsBox"></div>
      <div className="PanelsBox"></div>
    </div>
  );
}

首先,我们为App.js ,导入一个外部样式表。

然后我们创建了一个App 函数,它将在先前创建的index.js 中呈现。在它里面,我们创建了一个App div元素,这将是我们应用程序的主要包装器。此外,在App 包装器内,将有ControlsBoxPanelsBox 组件。

现在,打开App.css 文件并添加以下样式。

css
.App {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.ControlsBox {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

.PanelsBox {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
  gap: 20px;
  margin-top: 20px;
}

在这里,我们确保App 包装器不会超过特定的宽度。我们还把它放在视口的中心位置,并在里面添加了填充物。

对于ControlsBox ,我们将网格布局设置为两列,每列的宽度相同。我们还在两列之间添加了一个间隙。

PanelsBox 子节点也将使用两列的网格布局,两列之间有间隙。如果子节点的宽度小于400px ,布局将自动切换到一列,这意味着包含的EditorHighlighter 组件将显示在彼此的下方。

为了将PanelsBoxControlsBox 分开,我们在顶部添加了一个空白。

在React中用useState 钩子设置状态

数据将发生变化,因为在我们的应用程序中,将有用户选择语言和主题而触发的用户互动。为了在屏幕上正确显示它们,我们将需要把它们存储到状态变量中。

为此,我们将使用React内置的useState钩子,这是React生态系统中的一种标准处理方式。

打开App.js ,添加以下代码。

javascript
import React, { useState } from "react";
import "./App.css";

export default function App() {
  const [input, setInput] = useState("");
  const [language, setLanguage] = useState("");
  const [theme, setTheme] = useState("");

  return (
    <div className="App">
      <div className="ControlsBox"></div>
      <div className="PanelsBox"></div>
    </div>
  );
}

首先,我们导入React的useState 钩子,然后在App 函数中包含input,language, 和theme 变量。

input 将跟踪用户在 中的输入, 将跟踪用户选择的编程语言, 将跟踪用户选择的高亮主题。Editor language theme

创建组件

为了将应用程序的构件从应用程序的逻辑中划分出来,我们将创建几个组件,以便以后导入到App.js

我们将在项目的根目录下创建一个单独的文件夹,称为components ,并为DropdownEditorHighlighter 等组件创建单独的JS和CSS文件。

你可以手动创建这些文件,也可以使用终端命令mkdir components && cd components && touch Dropdown.js Dropdown.css Editor.js Editor.css Highlighter.js Highlighter.css 来节省时间。

Dropdown 组件

我们将使用Dropdown 组件进行语言和主题选择。唯一改变的变量将是我们将传入的数据。

打开Dropdown.js 文件,添加以下代码。

javascript
import "./Dropdown.css";

export const Dropdown = ({ defaultTheme, onChange, data }) => {
  return (
    <select className="select" defaultValue={defaultTheme} onChange={onChange}>
      {Object.keys(data)
        .sort()
        .map((theme, index) => {
          return (
            <option key={index} value={theme}>
              {theme}
            </option>
          );
        })}
    </select>
  );
};

在这个代码块中,我们首先导入了Dropdown.js 的外部样式表。

我们使用了select 元素,然后通过我们将从App 收到的data 道具进行循环,以显示可用的主题选项。然后我们按字母顺序对这些选项进行排序。

我们还使用了defaultProp ,这样我们以后就可以设置初始启动时显示的默认主题选项,以及onChange 道具,这样我们以后就可以控制当用户选择一个特定的主题时发生什么。

现在,切换到DropDown.css 文件,添加以下样式。

css
.select {
  height: "100px";
  border: none;
  border-radius: 5px;
  padding: 5px 0;
  background-color: #ffffff;
  width: 100%;
}

对于Select 组件,我们设置了具体的高度,去掉了默认的边框,圆了角,在里面添加了填充物,将背景设置为白色,并确保它在水平方向上使用了父体的所有可用空间。

创建Editor 组件

Editor 组件将是一个文本区域,用户将在这里输入代码。打开Editor.js 文件并添加以下代码。

javascript
import "./Editor.css";

export const Editor = ({ placeHolder, onChange, onKeyDown }) => {
  return (
    <textarea
      className="editor"
      placeholder={placeHolder}
      onChange={onChange}
    ></textarea>
  );
};

注意我们首先导入了Editor.js 的外部样式表。

然后我们返回了textarea 元素,并包含了placeholder 道具,它将在初始启动时显示占位符值。我们还包括了onChange 道具,这样我们就可以控制用户输入代码时发生的情况。

让我们给Editor 组件添加一些样式。打开Editor.css ,包括以下样式。

css
.editor {
  border: none;
  min-height: 300px;
  padding: 10px;
  resize: none;
}

对于Editor 组件,我们删除了默认的边框,设置了最小高度,并添加了填充。

我们还确保了编辑块不能被用户手动调整大小。它仍然会根据用户输入的内容自动调整其高度。

添加 react-syntax-highlighter 包

为了突出代码块,我们将使用react-syntax-highlighter包。要安装它,在你的终端上运行以下命令。

npm i react-syntax-highlighter

然后打开Highlighter.js 文件,包括以下代码。

javascript
import SyntaxHighlighter from "react-syntax-highlighter";
import "./Highlighter.css";

export const Highlighter = ({ language, theme, children }) => {
  return (
    <SyntaxHighlighter
      language={language}
      style={theme}
      className="highlighter"
    >
      {children}
    </SyntaxHighlighter>
  );
};

我们首先导入了SyntaxHighlighter 组件,然后为Highlighter.js ,导入了一个外部样式表。

SyntaxHighlighter 需要languagestyle 。一旦我们将Highlighter 导入到App.js ,我们将把这些传入。

接下来,打开Highlighter.css 文件并添加以下样式规则。

css
.highlighter {
  min-height: 300px;
}

这将确保Highlighter 组件总是使用最小高度,如果没有内容,这将很有用(避免组件自动缩小)。

创建应用程序的逻辑

在这一阶段,我们将把所有东西放在一起,使应用程序发挥作用。

打开App.js 文件,添加以下代码。

javascript
import React, { useState } from "react";

import { Dropdown } from "../components/Dropdown";
import { Editor } from "../components/Editor";
import { Highlighter } from "../components/Highlighter";

import * as themes from "react-syntax-highlighter/dist/esm/styles/hljs";
import * as languages from "react-syntax-highlighter/dist/esm/languages/hljs";

import "./App.css";

const defaultLanguage = <code>${"javascript" || Object.keys(languages).sort()[0]}<code>;
const defaultTheme = <code>${"atomOneDark" || Object.keys(themes).sort()[0]}<code>;

export default function App() {
  const [input, setInput] = useState("");
  const [language, setLanguage] = useState(defaultLanguage);
  const [theme, setTheme] = useState(defaultTheme);

  return (
    <div className="App">
      <div className="ControlsBox">
        <Dropdown
          defaultTheme={defaultLanguage}
          onChange={(e) => setLanguage(e.target.value)}
          data={languages}
        />
        <Dropdown
          defaultTheme={defaultTheme}
          onChange={(e) => setTheme(e.target.value)}
          data={themes}
        />
      </div>
      <div className="PanelsBox">
        <Editor
          placeHolder="Type your code here..."
          onChange={(e) => setInput(e.target.value)}
        />
        <Highlighter language={language} theme={themes[theme]}>
          {input}
        </Highlighter>
      </div>
    </div>
  );
}

让我们来分解一下这个代码块。

首先,我们从react-syntax-highlighter导入DropdownEditorHighlighter 组件,以及所有支持的主题和语言。

然后我们将defaultLanguage 变量设置为javascript 。如果它在我们导入的语言列表中不可用,我们就将defaultlanguage 设置为导入的语言列表中的第一个可用语言。对于defaultTheme 也是如此。

我们还将defaultTheme 变量设置为atomOneDark 。如果它在导入的主题列表中不可用,defaultTheme 的值将被设置为导入的主题列表中的第一个可用主题。

对于Dropdown 组件,我们设置了defaultLanguagedefaultTheme ,一旦应用程序首次渲染,它们就会显示。

请注意,当用户从下拉菜单中进行选择时,onChange 行为将更新languagetheme 的变量状态。

最后,我们传入了生成下拉选项列表的data 道具。

对于Editor 组件,我们设置了placeHolder 组件,以便在应用程序首次呈现时要求用户输入一些信息。它还设置了onChange 函数,在用户每次在Editor 中写东西时更新input 状态变量。

最后,对于Highlighter 组件,我们传入了language 变量状态--所以它知道要渲染哪种语言--以及themes 变量状态,所以它知道如何进行样式设计。

剩下的最后一件事就是测试我们的应用程序了!检查你的终端,看看开发服务器是否仍在运行(如果没有,请运行npm start ),然后打开浏览器。

你应该看到功能代码编辑器和高亮显示。

Final Code Editor Example

结论

在本教程中,我们学习了如何为一个应用程序创建一个线框,使用状态,创建组件,对它们进行样式设计,以及创建应用程序的逻辑。

从现在开始,每次你需要挑选最合适的主题时,你都不需要再建立一个测试应用程序。现在,你将拥有自己的工具,可以使用!

在未来,你可以通过添加认证系统和数据库来进一步定制该项目,以便用户可以保存他们的片段,创建一个全栈的游乐场。

我希望你能从这个教程中学到一两点东西。谢谢你的阅读!

The postBuilding a React code editor and syntax highlighter from scratchappeared first onLogRocket Blog.