React教程—从零开始建立一个计算器应用程序

178 阅读6分钟

React Tutorial: Build a Calculator App from Scratch

在本教程中,我们将构建一个React计算器应用程序。你将学习如何制作一个线框,设计一个布局,创建组件,更新状态,以及格式化输出。

为了激发你的灵感,这里有一个链接,可以看到我们要构建的部署项目

另外,这里有源代码,如果你在项目的任何阶段需要帮助,可以参考一下。

计划

由于我们将建立一个计算器应用程序,让我们选择一个范围,不要太复杂的学习,但也不要太基本,以涵盖创建一个应用程序的不同方面。

我们要实现的功能包括。

  • 加法、减法、乘法、除法
  • 支持小数点值
  • 计算百分比
  • 反转数值
  • 重置功能
  • 格式化较大的数字
  • 根据长度调整输出大小

首先,我们要画一个基本的线框来显示我们的想法。为此,你可以使用FigmaDiagrams.net这样的免费工具。

Wireframe

请注意,在这个阶段,考虑颜色和造型并不那么重要。最重要的是,你可以构建布局并确定所涉及的组件。

设计颜色

一旦我们处理好了布局和组件,完成设计所要做的就是选择一个漂亮的颜色方案。

下面是一些使应用程序看起来很棒的准则。

  • 封装器应与背景形成对比
  • 屏幕和按钮的数值应易于阅读
  • 等号按钮应采用不同的颜色,以突出其重要性。

基于上述标准,我们将使用如下所示的颜色方案。

Color scheme

设置项目

要开始,在你的项目文件夹中打开终端,使用create-react-app创建一个模板。要做到这一点,运行该命令。

npx create-react-app calculator

这是最快和最简单的方法来设置一个完全工作的React应用,而且是零配置。之后你需要做的就是运行cd calculator ,切换到新创建的项目文件夹,然后npm start ,在浏览器中启动你的应用程序。

Browser view

正如你所看到的,它带有一些默认的模板,所以接下来我们要在项目文件夹树中做一些清理工作。

找到src 文件夹,你的应用程序的逻辑将在这里,并删除除App.js 创建你的应用程序,index.css 样式你的应用程序,以及index.js 在DOM中渲染你的应用程序之外的所有东西。

Project tree

创建组件

由于我们已经做了一些线框设计,我们已经知道了应用程序的主要构建模块。这些是WrapperScreenButtonBoxButton

首先在src 文件夹内创建一个components 文件夹。然后我们将为每个组件创建一个单独的.js 文件和.css 文件。

如果你不想手动创建这些文件夹和文件,你可以使用下面的单行代码来快速完成设置。

cd src && mkdir components && cd components && touch Wrapper.js Wrapper.css Screen.js Screen.css ButtonBox.js ButtonBox.css Button.js Button.css

包裹者

Wrapper 组件将是一个框架,将所有的子组件固定在一起。它也将允许我们在之后将整个应用程序居中。

Wrapper.js

import "./Wrapper.css";

const Wrapper = ({ children }) => {
  return <div className="wrapper">{children}</div>;
};

export default Wrapper;

Wrapper.css

.wrapper {
  width: 340px;
  height: 540px;
  padding: 10px;
  border-radius: 10px;
  background-color: #485461;
  background-image: linear-gradient(315deg, #485461 0%, #28313b 74%);
}

屏幕

Screen 组件将是Wrapper 组件的顶部部分子组件,其目的是显示计算值。

在功能列表中,我们包括显示输出在长度上的大小调整,这意味着较长的值必须缩小尺寸。我们将使用一个小的(3.4kb的gzip)库,叫做react-textfit,用于此。

要安装它,运行npm i react-textfit ,然后导入并使用它,如下图所示。

Screen.js

import { Textfit } from "react-textfit";
import "./Screen.css";

const Screen = ({ value }) => {
  return (
    <Textfit className="screen" mode="single" max={70}>
      {value}
    </Textfit>
  );
};

export default Screen;

Screen.css

.screen {
  height: 100px;
  width: 100%;
  margin-bottom: 10px;
  padding: 0 10px;
  background-color: #4357692d;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  color: white;
  font-weight: bold;
  box-sizing: border-box;
}

按钮盒

ButtonBox 组件,与Wrapper 组件类似,将成为子程序的框架 - 只是这次是为Button 组件。

ButtonBox.js

import "./ButtonBox.css";

const ButtonBox = ({ children }) => {
  return <div className="buttonBox">{children}</div>;
};

export default ButtonBox;

ButtonBox.css

.buttonBox {
  width: 100%;
  height: calc(100% - 110px);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(5, 1fr);
  grid-gap: 10px;
}

按钮

Button 组件将为应用程序提供互动性。每个组件都会有valueonClick 道具。

在样式表中,我们也将包括equal 按钮的样式。以后我们将使用Button props来访问这个类。

Button.js

import "./Button.css";

const Button = ({ className, value, onClick }) => {
  return (
    <button className={className} onClick={onClick}>
      {value}
    </button>
  );
};

export default Button;

Button.css

button {
  border: none;
  background-color: rgb(80, 60, 209);
  font-size: 24px;
  color: rgb(255, 255, 255);
  font-weight: bold;
  cursor: pointer;
  border-radius: 10px;
  outline: none;
}

button:hover {
  background-color: rgb(61, 43, 184);
}

.equals {
  grid-column: 3 / 5;
  background-color: rgb(243, 61, 29);
}

.equals:hover {
  background-color: rgb(228, 39, 15);
}

渲染元素

React应用程序中渲染的基础文件是index.js 。在我们进一步讨论之前,确保你的index.js 看起来如下。

import React from "react";
import ReactDOM from "react-dom";

import App from "./App";
import "./index.css";

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

另外,让我们检查一下index.css ,确保我们重置了paddingmargin 的默认值,挑选一些很棒的字体(在本例中像Montserrat),并设置适当的规则以使应用程序在视口中居中。

@import url("https://fonts.googleapis.com/css2?family=Montserrat&display=swap");

* {
  margin: 0;
  padding: 0;
  font-family: "Montserrat", sans-serif;
}

body {
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #fbb034;
  background-image: linear-gradient(315deg, #fbb034 0%, #ffdd00 74%);
}

最后,让我们打开主文件App.js ,并导入我们之前创建的所有组件。

import Wrapper from "./components/Wrapper";
import Screen from "./components/Screen";
import ButtonBox from "./components/ButtonBox";
import Button from "./components/Button";

const App = () => {
  return (
    <Wrapper>
      <Screen value="0" />
      <ButtonBox>
        <Button
          className=""
          value="0"
          onClick={() => {
            console.log("Button clicked!");
          }}
        />
      </ButtonBox>
    </Wrapper>
  );
};

export default App;

在上面的例子中,我们只渲染了一个Button 组件。

让我们为线框中的数据创建一个数组表示,这样我们就可以映射并渲染ButtonBox 中的所有按钮。

import Wrapper from "./components/Wrapper";
import Screen from "./components/Screen";
import ButtonBox from "./components/ButtonBox";
import Button from "./components/Button";

const btnValues = [
  ["C", "+-", "%", "/"],
  [7, 8, 9, "X"],
  [4, 5, 6, "-"],
  [1, 2, 3, "+"],
  [0, ".", "="],
];

const App = () => {
  return (
    <Wrapper>
      <Screen value=0 />
      <ButtonBox>
        {
          btnValues.flat().map((btn, i) => {
            return (
              <Button
                key={i}
                className={btn === "=" ? "equals" : ""}
                value={btn}
                onClick={() => {
                  console.log(`${btn} clicked!`);
                }}
              />
            );
          })
        }
      </ButtonBox>
    </Wrapper>
  );
};

检查你的终端,确保你的React应用仍在运行。如果没有,运行npm start ,再次启动它。

打开你的浏览器。如果你跟着做,你当前的结果应该是这样的。

App design

如果你愿意,你也可以打开浏览器的devtools,测试一下每个按钮按下的日志值。

Console.log

定义状态

接下来,我们将使用ReactuseState 钩子声明状态变量。

具体来说,会有三个状态。num,输入值;sign ,选择的符号:和res ,计算值。

为了使用useState 钩子,我们必须首先在App.js 中导入它。

import React, { useState } from "react";

App 函数中,我们将使用一个对象来一次性设置所有状态。

import React, { useState } from "react";

// ...

const App = () => {
  let [calc, setCalc] = useState({
    sign: "",
    num: 0,
    res: 0,
  });

  return (
    // ...
  );
};

继续阅读React教程。SitePoint从零开始建立一个计算器应用程序