Демо этого проекта находится здесь
Проверка формы важна, если ваше веб-приложение имеет форму, которую пользователь может отправлять на определенный сервер. Прежде чем пользователь сможет отправить данные на сервер, важно убедиться, что данные в форме верны, прежде чем отправлять их на сервер или в базу данных.
Существует 2 разных типа проверки формы, которые должен понимать каждый разработчик. Во-первых, проверки на стороне клиента, которые в основном касаются JavaScript в браузерах, и, во-вторых, проверки на стороне сервера, что означает проверку данных на стороне сервера или в бэкенде вашего приложения.
Проверка на стороне клиента или проверка внешнего интерфейса — это способ сообщить пользователю, что заполненные данные верны или неверны. Однако проверки на стороне клиента — не единственное решение для безопасности вашей формы. Проверка на стороне клиента может быть легко отключена в браузере, поэтому вам нужен второй уровень проверки, то есть проверка на стороне сервера.
В этой статье мы рассмотрим только проверки на стороне клиента.
Существует несколько способов реализовать проверки на стороне клиента. В этом руководстве мы будем использовать Tailwind CSS, который является отличным внешним интерфейсом для CSS.
1. Создайте свой проект
Откройте свой терминал и создайте новый проект с помощью Vite. Я назвал его tailwind-form-validations
, но вы можете дать любое другое имя. Кроме того, мы передаем флаг --template react
, поскольку он говорит Vite создать проект React.
npm create vite@latest tailwind-form-validations -- --template react
После создания проекта перейдите к нему с помощью следующей команды:
cd tailwind-form-validations
Затем установите Tailwind CSS с помощью этой команды:
npm install -D tailwindcss postcss autoprefixer
Затем создайте файл конфигурации Tailwind:
npx tailwindcss init -p
Затем замените раздел содержимого в файле tailwind.config.js
следующим кодом:
content: [ "./index.html", "./src/**/*.{js,ts,jsx,tsx}", ],
Наконец, добавьте директивы Tailwind в ваш файл index.css
:
@tailwind base; @tailwind components; @tailwind utilities;
Кроме того, я добавил дополнительные пакеты для иконок и CSS-форм Tailwind. Вы также можете установить их, если хотите. Просто скопируйте и вставьте следующие команды в свой терминал:
npm install react-icons --save npm install -D @tailwindcss/forms
Поскольку вы установили CSS-формы Tailwind, обязательно добавьте их в файл конфигурации Tailwind. Добавьте его в раздел плагинов конфигурационного файла Tailwind следующим образом:
plugins: [ require('@tailwindcss/forms'), // ... ],
2. Создайте компоненты и файл данных
Создайте компонент Button.jsx в каталоге src/components
и вставьте в этот файл следующий код:
const Button = ({ title, icon, ariaLabel }) => { return ( <button aria-label={ariaLabel} type="button" className="flex w-full items-center justify-center space-x-4 rounded-md border border-gray-300 bg-gray-100 py-3 hover:border-purple-400 hover:bg-gray-200 focus:ring-2 focus:ring-purple-400 focus:ring-offset-1 dark:border-gray-700 dark:bg-gray-800 dark:hover:border-purple-600 dark:hover:bg-gray-600" > {icon} <p>{title}</p> </button> ); }; export default Button;
Мы создали этот компонент Button, так как будем повторно использовать его в нашей форме.
Затем создайте файл countries.js в каталоге src/data
и вставьте туда следующий код:
export const countries = [ { name: 'Afghanistan', code: 'AF' }, { name: 'Åland Islands', code: 'AX' }, { name: 'Albania', code: 'AL' }, { name: 'Algeria', code: 'DZ' }, { name: 'American Samoa', code: 'AS' }, { name: 'AndorrA', code: 'AD' }, { name: 'Angola', code: 'AO' } .............. .............. ];
Файл countries.js
— это длинный файл, содержащий список всех стран мира. Я только что добавил первые несколько стран в наш код, но вы можете получить полный список стран в формате JSON здесь и вставить его в свой файл countries.js
.
3. Форма проверки
Замените код в файле App.jsx следующим кодом:
import { useState } from 'react'; import { FiGithub, FiTwitter } from 'react-icons/fi'; import Button from './components/Button'; import { countries } from './data/countries'; function App() { const [data, setData] = useState({ fullName: '', email: '', country: '', password: '' }); const handleRegistration = (e) => { e.preventDefault(); console.log(data); }; // Destructure data const { ...allData } = data; // Disable submit button until all fields are filled in const canSubmit = [...Object.values(allData)].every(Boolean); return ( <div className="flex min-h-screen items-center justify-center px-4"> <div className="flex w-full flex-col items-center py-10 sm:justify-center"> <div className="w-full max-w-sm rounded-md bg-white px-6 py-6 shadow-md dark:bg-gray-900 sm:rounded-lg"> <form action="" onSubmit={handleRegistration} className="group" > <div> <label htmlFor="fullName" className="mb-2 block text-sm font-medium text-gray-900 dark:text-white" > Full Name </label> <div className="flex flex-col items-start"> <input type="text" name="fullName" placeholder="Full Name" className="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 placeholder-gray-300 focus:border-purple-500 focus:ring-purple-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-purple-500 dark:focus:ring-purple-500 [&:not(:placeholder-shown):not(:focus):invalid~span]:block invalid:[&:not(:placeholder-shown):not(:focus)]:border-red-400 valid:[&:not(:placeholder-shown)]:border-green-500" pattern="[0-9a-zA-Z ]{6,}" required onChange={(e) => { setData({ ...data, fullName: e.target.value }); }} /> <span className="mt-1 hidden text-sm text-red-400"> Full name must be at least 6 characters long </span> </div> </div> <div className="mt-4"> <label htmlFor="email" className="mb-2 block text-sm font-medium text-gray-900 dark:text-white" > Email </label> <div className="flex flex-col items-start"> <input type="email" name="email" placeholder="Email" className="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 placeholder-gray-300 focus:border-purple-500 focus:ring-purple-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-purple-500 dark:focus:ring-purple-500 [&:not(:placeholder-shown):not(:focus):invalid~span]:block invalid:[&:not(:placeholder-shown):not(:focus)]:border-red-400 valid:[&:not(:placeholder-shown)]:border-green-500" autoComplete="off" required pattern="[a-z0-9._+-]+@[a-z0-9.-]+\.[a-z]{2,}$" onChange={(e) => { setData({ ...data, email: e.target.value }); }} /> <span className="mt-1 hidden text-sm text-red-400"> Please enter a valid email address.{' '} </span> </div> </div> <div className="mt-4"> <label htmlFor="country" className="mb-2 block text-sm font-medium text-gray-900 dark:text-white" > Select your country </label> <select id="country" className="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-purple-500 focus:ring-purple-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-purple-500 dark:focus:ring-purple-500" onChange={(e) => { setData({ ...data, country: e.target.value }); }} > {countries.map((country) => ( <option key={country.code} value={country.code} > {country.name} </option> ))} </select> </div> <div className="mt-4"> <label htmlFor="password" className="mb-2 block text-sm font-medium text-gray-900 dark:text-white" > Password </label> <div className="flex flex-col items-start"> <input type="password" name="password" placeholder="Password" className="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 placeholder-gray-300 focus:border-purple-500 focus:ring-purple-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-purple-500 dark:focus:ring-purple-500 [&:not(:placeholder-shown):not(:focus):invalid~span]:block invalid:[&:not(:placeholder-shown):not(:focus)]:border-red-400 valid:[&:not(:placeholder-shown)]:border-green-500" autoComplete="off" required pattern="[0-9a-zA-Z]{8,}" onChange={(e) => { setData({ ...data, password: e.target.value }); }} /> <span className="mt-1 hidden text-sm text-red-400"> Password must be at least 8 characters.{' '} </span> </div> </div> <div className="mt-4"> <label htmlFor="password_confirmation" className="mb-2 block text-sm font-medium text-gray-900 dark:text-white" > Confirm Password </label> <div className="flex flex-col items-start"> <input type="password" name="password_confirmation" placeholder="Confirm password" className="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 placeholder-gray-300 focus:border-purple-500 focus:ring-purple-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-purple-500 dark:focus:ring-purple-500 [&:not(:placeholder-shown):not(:focus):invalid~span]:block invalid:[&:not(:placeholder-shown):not(:focus)]:border-red-400 valid:[&:not(:placeholder-shown)]:border-green-500" autoComplete="off" required pattern="[0-9a-zA-Z]{8,}" onChange={(e) => { setData({ ...data, password: e.target.value }); }} /> <span className="mt-1 hidden text-sm text-red-400"> Password must be at least 8 characters.{' '} </span> </div> </div> <a href="#" className="pt-1 text-xs text-purple-600 hover:text-purple-800 hover:underline dark:text-purple-300 dark:hover:text-purple-100" > Forget Password? </a> <div className="mt-4 flex items-center"> <button type="submit" disabled={!canSubmit} className="mt-2 w-full rounded-lg bg-purple-700 px-5 py-3 text-center text-sm font-medium text-white hover:bg-purple-600 focus:outline-none focus:ring-1 focus:ring-blue-300 disabled:cursor-not-allowed disabled:bg-gradient-to-br disabled:from-gray-100 disabled:to-gray-300 disabled:text-gray-400 group-invalid:pointer-events-none group-invalid:bg-gradient-to-br group-invalid:from-gray-100 group-invalid:to-gray-300 group-invalid:text-gray-400 group-invalid:opacity-70" > Create account </button> </div> </form> <div className="text-md mt-4 text-zinc-600 dark:text-zinc-300"> Already have an account?{' '} <span> <a className="text-purple-600 hover:text-purple-800 hover:underline dark:text-purple-400 dark:hover:text-purple-100" href="#" > Login instead </a> </span> </div> <div className="my-4 flex w-full items-center"> <hr className="my-8 h-px w-full border-0 bg-gray-200 dark:bg-gray-700" /> <p className="px-3 ">OR</p> <hr className="my-8 h-px w-full border-0 bg-gray-200 dark:bg-gray-700" /> </div> <div className="my-6 space-y-2"> <Button title="Continue with Github" ariaLabel="Continue with Github" icon={<FiGithub className="text-xl" />} /> <Button title="Continue with Twitter" ariaLabel="Continue with Twitter" icon={<FiTwitter className="text-xl" />} /> </div> </div> <div className="mt-6 flex items-center justify-center "> <a href="https://github.com/realstoman/tailwind-form-validations" target="__blank" className="cursor-pointer text-xl text-gray-700 underline hover:text-gray-900" > Github repo </a> </div> </div> </div> ); } export default App;
Это фактическая форма, которая имеет правила проверки в полях ввода. Ниже приведено краткое описание файла:
- Мы создаем состояние данных, которое будет содержать значения формы.
- Мы деструктурируем все данные в allData, используя синтаксис распространения.
- Затем мы создаем переменную canSubmit, которая обеспечивает заполнение всех полей перед отправкой.
- Каждое поле ввода имеет необходимые классы проверки из Tailwind CSS, метод onChange, который сохраняет обновленный ввод или выбирает значение, а также шаблон, построенный с использованием регулярного выражения.
- Затем мы передаем !canSubmit, который переключит состояние формы на отключенное свойство в кнопке.
- И последнее, но не менее важное: мы используем компонент кнопки, который мы создали, чтобы продолжить работу с Github и Twitter.
Совет. Вы можете извлечь поля ввода и выбрать поля, чтобы разделить повторно используемые компоненты, чтобы уменьшить размер файла App.jsx.
Исходный код для этого руководства доступен в моей учетной записи Github здесь: https://github.com/realstoman/tailwind-form-validations.
Заключение
В этой статье рассмотрено следующее:
- Создание проекта React с помощью Vite
- Добавление CSS Tailwind в React
- Создание повторно используемых компонентов
- Проверка форм с помощью Tailwind CSS