Здравствуйте! Давно не виделись. Хотя теперь, когда экзамены по информатике AP закончились, а лето почти наступило (осталось 30 дней учебы), у меня, надеюсь, будет больше времени, которое я смогу посвятить проектам и написанию статей.
В нашей сегодняшней статье в блоге мы рассмотрим, как можно создать удовлетворительную волнистую анимацию текста с помощью Framer Motion, React и TypeScript.
Вот демонстрация проекта в CodeSandbox 👇.
Начало работы
Я знаю, что вы жаждете действий, так что давайте начнем! Начните с инициализации проекта React и TypeScript с помощью create-react-app.
npx create-react-app wavy-text --template typescript
cd wavy-text
Для этого нам нужно установить еще одну библиотеку под названием Framer Motion. Давайте установим ее!
yarn add framer-motion
# npm i framer-motion
Потрясающе! Наш проект правильно настроен. Давайте откроем наш App.tsx
, чтобы начать работу. Давайте заменим содержимое по умолчанию, чтобы начать работу.
import "./styles.css";
import WavyText from "./WavyText";
export default function App() {
return (
<div className="App">
<h1>Awesome Wavy Text!</h1>
</div>
);
}
Круто. Теперь перейдем к файлу src/styles.css
, чтобы настроить некоторые базовые стили для нашего приложения. Ничего особенного, но мы хотим, чтобы все выглядело красиво.
@import url("https://fonts.googleapis.com/css2?family=Lexend+Deca&display=swap");
body {
background: linear-gradient(
45deg,
hsl(272deg 75% 65%) 0%,
hsl(193deg 100% 50%) 50%,
hsl(162deg 84% 88%) 100%
);
}
.App {
font-family: "Lexend Deca", sans-serif;
display: flex;
flex-direction: column;
min-height: 100vh;
justify-content: center;
align-items: center;
}
h1 {
color: white;
font-size: 48px;
user-select: none;
}
Создание анимации
Потрясающе! Теперь, когда все эти скучные вещи настроены и работают, давайте перейдем к сути проекта.
Переключившись на React, давайте сначала импортируем то, что нам понадобится для этого проекта, и настроим реквизиты для компонента.
import { FC } from "react";
import { motion, Variants, HTMLMotionProps } from "framer-motion";
interface Props extends HTMLMotionProps<"div"> {
text: string;
delay?: number;
duration?: number;
}
Поскольку мы используем Motion, нам нужно использовать HTMLMotionProps для передачи реквизитов в наш HTML-компонент.
Давайте теперь начнем создавать наш компонент React function внутри нашего файла и передадим через него наши реквизиты.
const Letter: FC<Props> = ({
text,
delay = 0,
duration = 0.05,
...props
}: Props) => {
}
Здесь внутри мы должны взять наш текстовый ввод и преобразовать каждую букву в строке в массив строк. Для этого мы можем использовать функцию Array.from() в JavaScript, чтобы добиться именно того, чего мы хотим.
const letters = Array.from(text);
Обратите внимание, что если вы используете международный язык, вам может понадобиться Grapheme Splitter для разделения строк на отдельные символы, воспринимаемые пользователем, в отличие от символов, воспринимаемых компьютером. Поскольку наш текст на английском языке, это только добавит ненужные сложности и дополнительные шаги в наш проект, поэтому я не буду его добавлять 🙂
Отлично! Давайте теперь отобразим отдельные буквы в этом массиве под другой компонент.
return (
<motion.h1
style={{ display: "flex", overflow: "hidden" }}
{...props}
>
{letters.map((letter, index) => (
<motion.span key={index}>
{letter === " " ? "u00A0" : letter}
</motion.span>
))}
</motion.h1>
);
Наша функциональность анимации в основном работает… есть только небольшая проблема. Анимация выглядит ужасно. К счастью, мы можем использовать Variants в Framer Motion, чтобы решить нашу проблему.
Вне (или внутри — мы можем даже объявить их в новом файле и импортировать в него) нашего компонента WavyText
, мы можем создать две разные анимации для контейнера и дочернего элемента.
const container: Variants = {
hidden: {
opacity: 0
},
visible: (i: number = 1) => ({
opacity: 1,
transition: { staggerChildren: duration, delayChildren: i * delay }
})
};
const child: Variants = {
visible: {
opacity: 1,
y: 0,
transition: {
type: "spring",
damping: 12,
stiffness: 200
}
},
hidden: {
opacity: 0,
y: 20,
transition: {
type: "spring",
damping: 12,
stiffness: 200
}
}
};
Теперь, когда мы это сделали, мы можем установить variants
в наших компонентах на соответствующую анимацию.
<motion.h1
style={{ display: "flex", overflow: "hidden" }}
variants={container}
initial="hidden"
animate="show"
{...props}
>
…и в нашем дочернем компоненте:
<motion.span key={index} variants={child}>
Ура — наша анимация теперь работает! Нам осталось импортировать ее в наш файл src/App.tsx
и правильно настроить.
Откройте файл src/App.tsx
. Начните с импорта вашего компонента, а затем удалите элемент <h1></h1>
и замените его на:
// import WavyText from "./WavyText";
// ...
<WavyText text="Awesome Wavy Text!" />
Замечательно! Теперь наша анимация должна работать так, как мы ожидали. В моем примере я также реализовал функцию «воспроизведения», если вам интересно взглянуть на код, стоящий за этим, обязательно загляните на CodeSandbox.
Заключение
Вот и все, что у меня есть для вас! Надеюсь, вы узнали что-то новое, и в дальнейшем сможете использовать эту анимацию для оживления своих сайтов! Я также сейчас использую эту анимацию на своем сайте 🙂
Если вы хотите увидеть больше статей о дизайне, a11y и смежных областях в моем блоге — дайте мне знать! Я с нетерпением жду ваших отзывов.
Приятного остатка дня 👋