Tarjeta de expansión animada usando framer-motion y ReactJS

En este artículo, vamos a aprender cómo crear una tarjeta de expansión animada usando React y Framer.

requisitos previos:

  1. Conocimiento de JavaScript (ES6).

    Los métodos incorporados de JavaScript que vamos a utilizar son:

    1. Función de flecha (ES6)
    2. operador ternario
    3. Objetos en JavaScript
  2. Conocimientos de HTML/CSS.
  3. Conocimientos básicos de ReactJS

Los ganchos de reacción utilizados en la construcción de esta aplicación son:

  1. Reaccionar estado de uso

Framer: los componentes y ganchos que vamos a utilizar en este tutorial son:

  1. https://www.framer.com/api/frame/
  2. https://www.framer.com/api/scroll/
  3. https://www.framer.com/api/utilities/#useanimation

Creación de la aplicación React e instalación del módulo:

  • Paso 1: Ahora, comenzará un nuevo proyecto usando create-react-app, así que abra su terminal y escriba.

    $npx create-react-app animated-card
  • Paso 2: después de crear la carpeta de su proyecto, es decir, la tarjeta animada, muévase a ella con el siguiente comando.

    $cd animated-card
  • Paso 3: agregue los paquetes npm que necesitará durante el proyecto.

    $npm install framer react-icons
    // For yarn
    $yarn add framer react-icons

Abra la carpeta src y elimine los siguientes archivos:

  1. logotipo.svg
  2. serviceWorker.js
  3. setupTests.js
  4. Aplicación.css
  5. Aplicación.js
  6. App.test.js (si corresponde)

Cree un archivo llamado Card.js.

Estructura del proyecto: el árbol de estructura de su proyecto debería verse así:

Estructura del proyecto

Ejemplo: 

index.js

import React from "react";
import { Frame, Scroll } from "framer";
import Card from "./Card";
import ReactDOM from "react-dom";
  
import "./index.css";
  
// main App HOC
export const App = () => {
  return (
    <Frame height={"100%"} width={"100%"} background={"#333"}>
      <Frame width={375} height={"100%"} background={"#FFF"} center>
        <Scroll width={375} height={"100%"}>
          {/* Card component with props yPos,title,subtitle */}
          <Card
            yPos={48}
            title={"GEEKSFORGEEKS"}
            subtitle="Don't learn alone"
          />
          <Card
            yPos={48 + 300 + 24}
            title={"reactJS"}
            subtitle="Most starred JavaScript library"
          />
        </Scroll>
      </Frame>
    </Frame>
  );
};
  
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

index.css

body {
  margin: 0;
  cursor: pointer;
}

Card.js

import React, { useState } from "react";
import { ImCross } from "react-icons/im";
import { Frame, Scroll, useAnimation } from "framer";
  
// Card component with destructured props :
// yPos, title, subtitle
const Card = ({ yPos, title, subtitle }) => {
  
  // useState hook to manage the state of
  // expanding of card
  const [state, setState] = useState(false);
  
  // utility function to handle
  // onTap on card component
  const handleTap = () => {
    state ? controls.start({ y: 0 }) : setState(!state);
  };
  
  const controls = useAnimation();
  
  // Variants allow you to define animation
  // states and organise them by name.
  // They allow you to control animations 
  // throughout a component
  // tree by switching a single animate prop.
  const variants = {
    active: {
      width: 320,
      height: 800,
      borderRadius: 0,
      overflow: "visible",
      left: 28,
      right:0,
      y: 0,
      transition: { duration: 0.125, 
                    type: "spring", 
                    damping: 10, 
                    mass: 0.6 }
    },
    inactive: {
      width: 280,
      height: 280,
      borderRadius: 24,
      overflow: "hidden",
      left: 45,
      y: yPos,
      transition: { duration: 0.125, 
                    type: "spring", 
                    damping: 10,
                    mass: 0.6 }
    }
  };
  
  return (
    // basic container for layout, styling,
    // animation and events.
    <Frame
      y={yPos}
      variants={variants}
      animate={state ? "active" : "inactive"}
      width={300}
      height={300}
      borderRadius={24}
      style={state ? { zIndex: 10 } : { zIndex: 1 }}
      left={37.5}
      onTap={handleTap}
      shadow={
        state
          ? "0 0 0 0 rgba(0, 0, 0, 0)"
          : "0px 0px 20px 0px rgba(0, 0, 0, .25)"
      }
    >
      <Scroll
        width="100%"
        height="100%"
        backgroundColor={null}
        scrollAnimate={controls}
      >
        <Frame
          position="relative"
          backgroundColor={"#09a960"}
          width="100%"
          height={300}
        />
        <Frame position="relative" 
               height={1200} 
               background="white" />
  
        <Frame
          top={20}
          left={20}
          height={""}
          width={""}
          background={null}
          style={{
            color: "white",
            fontFamily: "sans-serif"
          }}
        >
          <span style={{ fontSize: "1.6em", 
                         fontWeight: 600 }}>
                        {title}
          </span>
          <br />
          <span
            style={{
              fontSize: "1em",
              fontWeight: 500,
              opacity: 0.5
            }}
          >
            {subtitle}
          </span>
        </Frame>
      </Scroll>
      {state && (
        <Frame
          borderRadius={20}
          size={15}
          top={15}
          right={20}
          backgroundColor={"#09a960"}
          onTap={() => {
            setState(false);
          }}
        >
          <ImCross color="red" />
        </Frame>
      )}
    </Frame>
  );
};
  
export default Card;

Paso para ejecutar la aplicación: Ejecute la aplicación usando el siguiente comando desde el directorio raíz del proyecto.

npm start

Salida: Ahora abra su navegador y vaya a http://localhost:3000/, verá la siguiente salida:

Publicación traducida automáticamente

Artículo escrito por jt9999709701 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *