构建具有React本地和后风CSS的计算器应用程序
#javascript #教程 #react #reactnative

最近,我完成了一门React本地课程,在这里我写了有关我的第一个项目 - 计算器应用程序。 ð

我决定从小型项目开始,然后才进入复杂的移动应用程序。因此,期望从我那里构建高级或复杂的移动应用程序的更多教程。

I've got this!

因此,在本教程中,我将带您了解如何使用React Native和Tailwind CSS构建移动计算器应用程序。

ðâps:本教程假设您在计算机上安装了本机和仿真器(或设备)。

什么是反应本地的?

React Native是一个开源式React框架,使您可以使用JavaScript代码为iOS和Android创建本机应用程序。尽管在本教程中,我们将使用Expo构建应用程序。

Expo使我们摆脱了使用React Native CLI创建本机应用程序所需的复杂配置,使其成为构建和发布React Antive Apps的最简单,最快的方法。

ðâ。亲爱的潜在雇主!我正在积极寻求远程机会,成为初级前端工程师(实习生)或技术作家,我可以在这里成长,学习和成长。这是我的portfolio and resume

项目设置

通过在下面运行代码段来创建一个新的Expo应用程序。

npx create-expo-app calculator-app

将本机风和尾风CSS作为项目的依赖性。

yarn add nativewind
yarn add --dev tailwindcss

ðââNativeWind使用尾风CSS作为脚本语言,因此使我们能够使用Android和iOS React Antive Apps使用Tailwind CSS编写相同的样式。

运行npx tailwindcss init来创建一个tailwind.config.js文件并按照以下完成的tailwind.config.js文件更新。

module.exports = {
    content: [
        "./App.{js,jsx,ts,tsx}",
        "./<custom directory>/**/*.{js,jsx,ts,tsx}",
    ],
    theme: {
        extend: {},
    },
    plugins: [],
};

最后,将babel插件添加到babel.config.js

// babel.config.js
module.exports = function (api) {
    api.cache(true);
    return {
        presets: ["babel-preset-expo"],
        plugins: ["nativewind/babel"],
    };
};

恭喜!ð您已成功配置了尾风CSS。现在,您可以使用尾风CSS样式。

构建应用程序用户界面

在本节中,您将学习如何为应用程序构建用户界面。

Application UI interface

从上图中,我们有一个大显示和一组按钮。接下来,创建一个返回包含数字和操作的按钮的组件。

Button Row

import { Pressable, Text, View } from "react-native";
import React from "react";

const ButtonGroup = ({
    first,
    second,
    third,
    fourth,
    handleNumberPress,
    handleOperationPress,
}) => {
    return (
        <View className='flex-row items-center w-full space-x-3 justify-center px-10 mb-2'>
            <Pressable
                className=' bg-white py-4 rounded-xl shadow-md w-1/4'
                onPress={() => handleNumberPress(first)}
            >
                <Text className='text-3xl text-gray-600 font-semibold text-center'>
                    {first}
                </Text>
            </Pressable>
            <Pressable
                className=' bg-white py-4   rounded-xl shadow-md w-1/4'
                onPress={() => handleNumberPress(second)}
            >
                <Text className='text-3xl text-gray-600 font-semibold text-center'>
                    {second}
                </Text>
            </Pressable>
            <Pressable
                className=' bg-white py-4 rounded-xl shadow-md w-1/4'
                onPress={() => handleNumberPress(third)}
            >
                <Text className='text-3xl text-gray-600 font-semibold text-center'>
                    {third}
                </Text>
            </Pressable>
            <Pressable
                className='bg-blue-600 py-4  rounded-xl shadow-md w-1/4'
                onPress={() => handleOperationPress(fourth)}
            >
                <Text className='text-3xl text-white font-semibold text-center'>
                    {fourth}
                </Text>
            </Pressable>
        </View>
    );
};

export default ButtonGroup;

上面的代码段接受按钮的每个值以及按下按钮时要执行的函数。组件中的最后一个按钮将包含一个操作;这就是为什么还有另一个功能-handleOperationPress用于其动作。

接下来,更新App.js文件以渲染下面的UI组件。

return (
    <SafeAreaView className='flex-1 items-center'>
        <View className='flex-1 w-full bg-blue-50 rounded-xl p-4 mb-4 items-end justify-end'>
            <Text className={`${firstNumber.length <= 7 ? "text-8xl" : "text-6xl"}`}>
                {display()}
            </Text>
        </View>

        <View className='w-full rounded-xl py-4'>
            {/* --- button container ---*/}
        </View>
    </SafeAreaView>
);

上面的代码段呈现计算器的显示屏幕。

使用下面的代码段渲染按钮。

<View className='w-full rounded-xl py-4'>
    <View className='flex-row items-center w-full space-x-3 justify-center px-10 mb-2'>
        <Pressable
            className='bg-gray-600 py-4   rounded-xl shadow-md w-1/4'
            onPress={() => clearScreen()}
        >
            <Text className='text-3xl text-white font-semibold text-center'>C</Text>
        </Pressable>
        <Pressable
            className='bg-gray-600 py-4   rounded-xl shadow-md w-1/4'
            onPress={() => changeSignFunction()}
        >
            <Text className='text-3xl text-white font-semibold text-center'>+/-</Text>
        </Pressable>
        <Pressable
            className='bg-gray-600 py-4 rounded-xl shadow-md w-1/4'
            onPress={() => percentageFunction()}
        >
            <Text className='text-3xl text-white font-semibold text-center'>%</Text>
        </Pressable>
        <Pressable
            className='bg-blue-600 py-4   rounded-xl shadow-md w-1/4'
            onPress={() => handleOperationPress("÷")}
        >
            <Text className='text-3xl text-white font-semibold text-center'>÷</Text>
        </Pressable>
    </View>
    <ButtonGroup
        first='7'
        second='8'
        third='9'
        fourth='x'
        handleNumberPress={handleNumberPress}
        handleOperationPress={handleOperationPress}
    />
    <ButtonGroup
        first='4'
        second='5'
        third='6'
        fourth='-'
        handleNumberPress={handleNumberPress}
        handleOperationPress={handleOperationPress}
    />
    <ButtonGroup
        first='1'
        second='2'
        third='3'
        fourth='+'
        handleNumberPress={handleNumberPress}
        handleOperationPress={handleOperationPress}
    />
    <View className='flex-row items-center w-full space-x-3 justify-center px-10 mb-2'>
        <Pressable
            className='bg-white py-4   rounded-xl shadow-md w-1/4'
            onPress={() => handleNumberPress(".")}
        >
            <Text className='text-3xl text-gray-600 font-semibold text-center'>
                .
            </Text>
        </Pressable>
        <Pressable
            className='py-4   rounded-xl shadow-md w-1/4'
            onPress={() => handleNumberPress("0")}
        >
            <Text className='text-3xl text-gray-600 font-semibold text-center'>
                0
            </Text>
        </Pressable>
        <Pressable
            className='bg-white py-4 rounded-xl items-center justify-center shadow-md w-1/4'
            onPress={() => deleteFunction()}
        >
            <Feather name='delete' size={24} color='black' />
        </Pressable>
        <Pressable
            className='bg-blue-600 py-4 rounded-xl shadow-md w-1/4'
            onPress={() => getResult()}
        >
            <Text className='text-3xl text-white font-semibold text-center'>=</Text>
        </Pressable>
    </View>
</View>

代码片段呈现屏幕上的按钮。我没有将ButtonGroup组件用于顶部和底部,因为它的功能和颜色与其他组件不同。

创建按钮功能

首先,您需要创建三个保持按钮值和操作的不同状态。

import { StatusBar } from "expo-status-bar";
import { Pressable, SafeAreaView, Text, View } from "react-native";
import ButtonGroup from "./components/ButtonGroup";
import { Feather } from "@expo/vector-icons";
import { useState } from "react";

export default function App() {
    const [firstNumber, setFirstNumber] = useState("");
    const [secondNumber, setSecondNumber] = useState("");
    const [operation, setOperation] = useState("");

    return <div>{/* --- UI components ---*/}</div>;
}

上面的代码段表明,用户可以将至少两个数字输入计算器和一个操作,除了百分比操作。

创建一个display函数,显示用户在屏幕上的输入。

const display = () => {
    if (!secondNumber && !firstNumber) {
        return "0";
    }
    if (!secondNumber) {
        return `${firstNumber}${operation}`;
    } else {
        return `${secondNumber}`;
    }
};

上面的功能检查用户是否尚未输入数字,然后返回“ 0”;否则,它将返回屏幕上的正确号码。

添加用户单击操作按钮时运行的函数。

const handleOperationPress = (value) => {
    if (
        firstNumber[firstNumber.length - 1] === "x" ||
        firstNumber[firstNumber.length - 1] === "+" ||
        firstNumber[firstNumber.length - 1] === "-" ||
        firstNumber[firstNumber.length - 1] === "%" ||
        firstNumber[firstNumber.length - 1] === "÷" ||
        operation !== ""
    ) {
        return;
    }
    setOperation(value);
};

上面的功能在更新operation状态之前检查了最后一个输入是否不是操作。

创建每次用户按数字时执行的另一个函数。

const handleNumberPress = (value) => {
    if (!operation && firstNumber.length < 10) {
        if (value !== ".") {
            setFirstNumber(firstNumber + value);
        } else {
            if (firstNumber.includes(".")) {
                return;
            } else {
                setFirstNumber(firstNumber + value);
            }
        }
    }
    if (operation && secondNumber.length < 10) {
        if (value !== ".") {
            setSecondNumber(secondNumber + value);
        } else {
            if (secondNumber.includes(".")) {
                return;
            } else {
                setSecondNumber(secondNumber + value);
            }
        }
    }
};

上面的功能检查用户是否已在设置firstNumbersecondNumber状态值之前输入操作。
当用户按一个数字按钮时,计算器将其值设置为firstNumber变量。将操作符号后的任何后续数字设置为secondNumber

创建等价函数,如下所示。

const getResult = () => {
    switch (operation) {
        case "+":
            clearScreen();
            setFirstNumber(parseFloat(firstNumber) + parseFloat(secondNumber));
            setOperation("");
            setSecondNumber("");
            break;
        case "-":
            clearScreen();
            setFirstNumber(parseFloat(firstNumber) - parseFloat(secondNumber));
            setOperation("");
            setSecondNumber("");
            break;
        case "x":
            clearScreen();
            setFirstNumber(parseFloat(firstNumber) * parseFloat(secondNumber));
            setOperation("");
            setSecondNumber("");
            break;
        case "÷":
            clearScreen();
            const value = parseInt(firstNumber) / parseInt(secondNumber);
            if (value !== Math.round(value) && value !== Math.trunc(value)) {
                setFirstNumber(value.toFixed(5));
            } else {
                setFirstNumber(value);
            }
            setOperation("");
            setSecondNumber("");
            break;
        default:
            clearScreen();
            break;
    }
};

上面的函数接受firstNumbersecondNumber的值并在值上执行正确的操作。

用户单击百分比函数时,它将返回百分比的值。

const percentageFunction = () => {
    if (!secondNumber) {
        return setFirstNumber(parseFloat(firstNumber) / 100);
    }
};

添加一个功能,使用户能够清除屏幕或删除最近输入的值。

//👇🏻 clears the screen
const clearScreen = () => {
    setFirstNumber("");
    setSecondNumber("");
    setOperation("");
};

//👇🏻 removes the recently entered value
const deleteFunction = () => {
    if (operation) {
        return setSecondNumber(secondNumber.slice(0, -1));
    }
    return setFirstNumber(firstNumber.toString().slice(0, -1));
};

最后,创建changeSignFunction函数,以使用户能够在计算器中输入负值和正值。该功能检查一个数字上的符号并切换。

const changeSignFunction = () => {
    if (operation) {
        if (secondNumber.startsWith("-")) {
            return setSecondNumber(secondNumber.replace("-", "+"));
        }
        if (secondNumber.startsWith("+")) {
            return setSecondNumber(secondNumber.replace("+", "-"));
        }
        return setSecondNumber(`-${secondNumber}`);
    } else {
        if (firstNumber.toString().startsWith("-")) {
            return setFirstNumber(firstNumber.toString().replace("-", "+"));
        }
        if (firstNumber.toString().startsWith("+")) {
            return setFirstNumber(firstNumber.toString().replace("+", "-"));
        }
        return setFirstNumber(`-${firstNumber}`);
    }
};

结论

正如我之前说过的,这是一个初学者的本地项目。希望它可以帮助您开始使用React Native或构建第一个移动应用程序。

您可以在GitHub上获取源代码,然后尝试一个项目here的演示。

感谢您的阅读! ð

向工作开放

您是否喜欢这篇文章,或者需要经验丰富的技术作家 / React开发人员,以担任远程,全职或基于合同的角色?随时与我联系。
GitHub || LinkedIn || Twitter

Buy David a coffee
Thank You