Мы создадим простой TextFormField, используя Javascript в качестве компонентов React, перед тем как начать, обязательно установите два пакета узлов: npm i sass, npm i react-icon.

Окончательный результат будет выглядеть примерно так:

Для версии быстрого кодирования и репозитория кода посмотрите видео ниже.

Сначала вы должны начать с создания папки, которая будет содержать ваши компоненты.

Папка будет содержать TextFormField jsx и scss.

Наш TextFormField будет содержать следующие параметры: значение, onChange, hasError, ширина, высота, начало, конец, подсказка, тип и заголовок.

Теперь нам нужно определить 4 ссылки.

const inputRef = useRef();
const leadingRef = useRef();
const trailingRef = useRef();
const hintRef = useRef();

эти ссылки позволят нам получить доступ к каждому элементу и их соответствующей ширине/высоте.

компонент вернет div, содержащий ввод и текст ошибки, он будет выглядеть примерно так:

return (
<div>
<div
className="TFF"
style={{
width: width,
height: height,
}}
>
<span className="TFFL" ref={leadingRef}>
{leading}
</span>
<input
type={type}
title={title}
value={value}
onChange={(e) => onChange(e.target.value)}
ref={inputRef}
style={{
width: width,
height: height,
}}
className={`${hasError ? "TFFE" : ""}`}
/>
<span className={`TFFHN ${value ? "TFFH" : ""}`} ref={hintRef}>
{hint}
</span>
<span className="TFFT" ref={trailingRef}>
{trailing}
</span>
</div>
<p className="TFFET">{hasError}</p>
</div>
);

теперь нам нужно применить некоторую магию css, чтобы сделать его похожим на настоящий TextFormField. Этого можно добиться с помощью абсолютного позиционирования.

.TFF {
display: flex;
position: relative;
font-size: 16px;
input {
width: 100%;
height: 100%;
outline: none;
border: 2px solid #666;
border-radius: 10px;
}
}

теперь нам нужно нацелиться на текст подсказки, который является нашим самым важным компонентом.

.TFFHN {
position: absolute;
top: calc(50% - 8px - 2px);
user-select: none;
pointer-events: none;
transition: background-color 0.3s, left 0.3s, top 0.3s;
}

события user-select и pointer-events делают текст подсказки недоступным для выбора. Чтобы отцентрировать его, мы применяем верхнее позиционирование 50% минус половина размера шрифта и 2 пикселя для границ. Когда на входе есть вход, который не пуст, класс TFFH будет применен, этот класс будет иметь следующий css

.TFFH {
left: 5px;
background-color: white;
top: calc(-50% + 5px + 8px);
left: 8px !important;
}

мы будем применять цвет основного фона, а также перемещать его вверх, что сделает его таким:

теперь мы должны убедиться, что ведущие и конечные элементы также имеют абсолютную позицию.

.TFFL {
position: absolute;
left: 0;
display: grid;
place-items: center;
height: 100%;
top: 0px;
z-index: 2;
}

конец будет иметь тот же код, но справа: 0px вместо слева.

Теперь, когда у нас есть основная функциональность, давайте попробуем добавить некоторые завершающие и ведущие значки, которые могут действовать как меню или кнопка, которая перемещает пользователя на какой-либо другой экран, предел — ваше воображение.

Внутри App.js мы импортируем текстовое поле со следующими значениями реквизита.

<TextFormField
hasError={fieldValueError}
hint="first name"
height="50px"
width="400px"
onChange={(e) => setFieldValue(e)}
title="some title"
value={fieldValue}
type="text"
leading={
<MdSearch
style={{
fontSize: "20px",
color: "#444",
padding: "0 5px",
cursor: "pointer",
}}
/>
}
trailing={
<MdMenu
style={{
fontSize: "20px",
color: "#444",
padding: "0 10px",
cursor: "pointer",
}}
/>
}
/>

обратите внимание, что fieldValue и fieldValueError оба являются состояниями реакции. Теперь наш компонент будет выглядеть примерно так:

Наконец, это не TextFormField без проверки ввода и анимации ошибок. Для этого у нас есть этот css

.TFFE {
animation: ErrorAnimation 0.3s forwards;
}
.TFFET {
color: rgb(228, 182, 182);
font-size: 14px;
padding: 0;
margin: 5px 10px;
}
@keyframes ErrorAnimation {
0% {
transform: translate(0px, 0px);
}
10% {
transform: translate(1px, 1px);
}
20% {
transform: translate(-1px, -1px);
}
30% {
transform: translate(1px, -1px);
}
40% {
transform: translate(-2px, 1px);
}
50% {
transform: translate(0px, 0px);
}
60% {
transform: translate(1px, 1px);
}
70% {
transform: translate(-1px, -1px);
}
80% {
transform: translate(-2px, 1px);
}
90% {
transform: translate(1px, 1px);
}
100% {
transform: translate(0px, 0px);
border: 2px solid rgb(228, 182, 182);
}
}

Если hasError не является пустой строкой, поле будет дрожать и станет красным, а текст ошибки появится со значением ошибки. это будет выглядеть примерно так

Для обработки ошибок давайте применим простую форму и кнопку отправки app.js

<form
onSubmit={(e) => {
e.preventDefault();
if (!checkValidity()) return;
// do logic
}}
>
<TextFormField
hasError={fieldValueError}
hint="first name"
height="50px"
width="400px"
onChange={(e) => setFieldValue(e)}
title="some title"
value={fieldValue}
type="text"
leading={
<MdSearch
style={{
fontSize: "20px",
color: "#444",
padding: "0 5px",
cursor: "pointer",
}}
/>
}
trailing={
<MdMenu
style={{
fontSize: "20px",
color: "#444",
padding: "0 10px",
cursor: "pointer",
}}
/>
}
/>
<button type="submit">submit</button>
</form>

наша функция checkValidty проверит поле на все, что вы хотите, это может быть проверка валидности электронной почты, проверка пустоты или проверка длины. Эти проверки могут быть сериализованы одна за другой.

function checkValidity() {
setFieldValueError(fieldValue ? "" : "cannot be empty");
if (!fieldValue) {
return false;
}
return true;
}

Это наша основная функция проверки достоверности, которая возвращает true, если форма действительна, и false, если нет.

Если вы хотите посмотреть видео о том, как я решаю эту задачу и скоростное кодирование, посмотрите это

Вот и все, наслаждайтесь кодированием :) !