Animation hay hiệu ứng động là một phần quan trọng trong mọi ứng dụng web hiện đại. Nó cũng là một trong số những phần khó thực hiện nhất. Và Framer Motion sẽ giúp bạn thực hiện việc đó dễ dàng.
Cách Framer Motion hoạt động
Framer Motion dùng thành phần chuyển động cho các animation. Mỗi phần tử HTML/SVG đều có một thành phần chuyển động tương đương với các thuật tính cho cử chỉ và hoạt ảnh. Ví dụ, một HTML thông thường, div trông sẽ như thế này:
<div> </div>
Framer Motion tương đương trông như thế này:
<motion.div> </motion.div>
Các thành phần motion hỗ trợ thuộc tính animate, kích hoạt hiệu ứng động khi giá trị của nó thay đổi. Đối với các hiệu ứng phức tạp, dùng hook useAnimate với tham chiếu có phạm vi.
Animation trong Framer Motion
Trước khi dùng Framer Motion trong dự án, bạn cần cài runtime Node.js và trình quản lý gói Yarn được cài trên máy tính và hiểu React là gì cũng như cách sử dụng nó.
Mở terminal và chạy:
git clone git@github.com:makeuseofcode/framer-motion-app.git
cd framer-motion-app
yarn
yarn dev
Khi mở localhost:5173 trong trình duyệt của bạn, bạn sẽ thấy:
Giờ bạn có thể tạo animation đơn giản đầu tiên, một nút bấm hiện khi trỏ chuột và thu hẹp khi con trỏ rời đi.
Mở file src/App.jsx trong trình chỉnh sửa code. File này chứa một thành phần chức năng trả về một đoạn React. Nhập thành phần Button, sau đó kết xuất nó, chuyển vào thuộc tính text:
<section>
<h4>Animated Button</h4>
<div>Move your mouse over the button to see the effect</div>
<Button text="Hover Me"/>
</section>
Tiếp theo, chỉnh sửa file Button.jsx và nhập tiện ích motion từ framer-motion:
import { motion } from "framer-motion"
Giờ, thay thế phần tử button thông thường bằng motion.[element]. Trong trường hợp này, dùng thành phần motion.button.
Sau đó thêm thuộc tính cử chỉ whileHover và chuyển một đối tượng của giá trị mà Framer Motion sẽ tạo hiệu ứng khi người dùng trỏ chuột qua nút bấm.
<motion.button whileHover={{ scale: 1.1 }}>
{text}
</motion.button>
Nút bấm này giờ sẽ tạo hiệu ứng động khi bạn di chuyển con trỏ chuột qua nó hoặc rời khỏi nó:
Có thể bạn đang tự hỏi tại sao bản thử nghiệm này không dùng hoạt ảnh CSS. Framer Motion có ưu điểm hơn CSS vì nó tích hợp với trạng thái React và thường cho code gọn gàng hơn.
Tiếp theo, thử một thứ gì đó phức tạp hơn: tạo hiệu ứng cho một modal. Trong Backdrop.jsx, nhập tiện ích motion và tạo thành phần chức năng bằng thuộc tính onClick và children. Quay lại thành phần motion.div với class “backdrop” và trình nghe onClick trong JSX.
export default function Backdrop() {
return (<>
<motion.div>
</motion.div>
</>)
}
Sau đó thêm 3 thuộc tính: initial, animate và exit. Những thuộc tính này đại diện cho trạng thái ban đầu của phần tử, trạng thái của phần tử sẽ chuyển động và trạng thái của thành phần sau khi chạy animation tương ứng.
Thêm thuộc tính onClick và children vào motion.div và đặt thời gian chuyển tiếp sang 0.34 giây.
export default function Backdrop ({onClick, children}){
return (<>
<motion.div
onClick={onClick}
className="backdrop"
initial={{ opacity: 0, backdropFilter:"blur(0px)" }}
animate={{ opacity: 1, backdropFilter:"blur(3.4px)" }}
exit={{ opacity: 0, backdropFilter:"blur(0px)"}}
transition={{
duration: 0.34,
}}
>
{children}
</motion.div>
</>)
}
Thành phần Backdrop là một wrapper cho Model. Click backdrop sẽ loại bỏ modal. Trong Modal.jsx, nhập motion và thành phần Backdrop. Thành phần chức năng mặc định chấp nhận thuộc tính: closeModal và text. Tạo một biến dưới dạng đối tượng.
const variants = {
initial: {
y: "-200%",
opacity: 1,
},
visible: {
y: "50%",
transition: {
duration: 0.1,
type: "spring",
damping: 32,
stiffness: 500
}
},
exit: {
y: "200%",
}
}
Quay lại thành phần motion.div được gói trong Backdrop với thuộc tính variant trỏ tới đối tượng biến. Các biến thể là một nhóm trạng thái animation được xác định trước mà thành phần có thể ở bên trong.
<Backdrop onClick={closeModal}>
<motion.div
onClick={(e) => e.stopPropagation()}
className="modal"
variants={variants}
initial='initial'
animate='visible'
exit='exit'
>
{text}
</motion.div>
</Backdrop>
Tiếp theo, bạn cần thêm chức năng hiện modal khi người dùng click vào nút bấm. Mở file App.jsx và nhập hook useState React và Modal.
import { useState } from "react";
import Modal from "./components/Modal";
Sau đó, tạo trạng thái modalOpen với giá trị mặc định được thiết lập sang false.
const [modalOpen, setModalOpen] = useState(false);
Tiếp theo xác định hàm closeModal thiết lập modalOpen sang false.
function closeModal() {
setModalOpen(false)
}
Ở phía trên đầu của đoạn React, xuất Modal theo điều kiện và chuyển thuộc tính text phù hợp với closeModal.
{modalOpen && <Modal text="This is a modal animated with Framer Motion"}
Sau đó, trong phần tử section thứ hai, xuất một thành phần button với trình xử lý sự kiện onClick mà đặt modalOpen sang false.
<button onClick={() => setModalOpen(true)}>Show Modal</button>
Bạn có thể nhận ra rằng React ngắt kết nối thành phần Modal từ DOM mà không phải hiệu ứng exit. Để khắc phục điều đó, bạn cần thành phần AnimatePresence. Nhập AnimatePresence từ framer-motion.
import {AnimatePresence} from 'framer-motion';
Giờ, gói thành phần Modal trong AnimatePresence và đặt thuộc tính initial sang false và mode sang wait.
<AnimatePresence initial={false} mode="wait">
{modalOpen && <Modal text="This is a modal animated with Framer Motion" closeModal={closeModal} />}
</AnimatePresence>
Thành phần AnimatePresence cho phép hiệu ứng exit hoàn thành trước khi React ngắt kết nối nó khỏi DOM.
Tạo hiệu ứng các thành phần khi cuộn trong Framer
Framer Motion có thể tạo hiệu ứng các thành phần khi cuộn bằng thuộc tính whileInView. Mở ScrollElement.jsx, và nhập tiện ích motion. Thay đổi div sang motion.div với class "scroll-element".
<motion.div
initial={{ opacity: 0, scale: 0, rotate: 14 }}
whileInView={{ opacity: 1, scale: 1, rotate: 0 }}
transition={{ duration: .8 }}
viewport={{ once: true }}
className='scroll-element'
>
Scroll Element
</motion.div>
Thuộc tính viewport trỏ tới một đối tượng đặt once sang true. Tiếp theo, trong file App.jsx, nhập thành phần ScrollElement và xác định một biến scrollElementCount chứa giá trị số nguyên.
let scrollElementCount=14;
Trong thành phần section cuối cùng, tạo một mảng với độ dài nhất định được xác định bằng scrollElementCount, ánh xạ qua từng phần tử của mảng và tạo một thành phần với một khóa độc đáo dựa trên index i.
{[...Array(scrollElementCount)].map((x, i) => <ScrollElement key={i} />)}
Giờ, quay lại trình duyệt, các thành phần animate sẽ cuộn chúng vào trình xem.
Trên đây là những điều bạn cần biết về Framer Motion tạo animate trong ứng dụng React. Hi vọng bài viết hữu ích với các bạn.