5 ótimas maneiras de animar aplicativos React em 2019



A animação nos aplicativos React é um tópico popular e discutido. O fato é que existem várias maneiras de criá-lo. Alguns desenvolvedores usam CSS adicionando tags às classes HTML. Ótima maneira, vale a pena usar. Mas, se você quiser trabalhar com tipos complexos de animações, reserve um tempo para estudar o GreenSock, que é uma plataforma popular e poderosa. Existem também muitas bibliotecas e componentes para criar animações. Vamos conversar sobre eles.

Este artigo descreve cinco maneiras de animar aplicativos React:

  • CSS
  • ReactTransitionGroup;
  • Animações de reação
  • Reagir-revelar;
  • TweenOne e Ant Design.

A Skillbox recomenda: O curso educacional on-line "Profissão Java-developer" .
Lembramos que: para todos os leitores de "Habr" - um desconto de 10.000 rublos ao se inscrever em qualquer curso Skillbox usando o código promocional "Habr".

Todos os exemplos estão disponíveis no repositório (a partir daqui, as fontes são inseridas no artigo em vez de figuras, como no artigo original).

CSS


Este método foi mencionado no início e é realmente bom. Se, em vez de importar as bibliotecas JavaScript e usá-las, o assembly for pequeno, o navegador não precisará de muitos recursos. E isso, é claro, afeta o desempenho do aplicativo. Se sua animação for relativamente simples, preste atenção neste método.

Um exemplo é um menu animado:



É relativamente simples, com uma propriedade CSS e um gatilho como className = "is-nav-open" para a tag HTML.

Existem várias maneiras de usar esse método. Por exemplo, crie um wrapper sobre a navegação e, em seguida, chame as alterações de campo. Como a navegação tem uma largura constante de 250px, a largura do wrapper com a propriedade margin-left ou translateX deve ter a mesma largura. Se você precisar mostrar a navegação, adicione className = "is-nav-open" para o wrapper e mova o wrapper para margin-left / translateX: 0;.

Por fim, a fonte da animação ficará assim:

export default class ExampleCss extends Component { handleClick() { const wrapper = document.getElementById('wrapper'); wrapper.classList.toggle('is-nav-open') } render() { return ( <div id="wrapper" className="wrapper"> <div className="nav"> <icon className="nav__icon" type="menu-fold" onClick={() => this.handleClick()}/> <div className="nav__body"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Beatae ducimus est laudantium libero nam optio repellat sit unde voluptatum? </div> </div> </div> ); } } 

E aqui estão os estilos CSS:

 .wrapper { display: flex; width: 100%; height: 100%; transition: margin .5s; margin: 0 0 0 -250px; } .wrapper.is-nav-open { margin-left: 0; } .nav { position: relative; width: 250px; height: 20px; padding: 20px; border-right: 1px solid #ccc; } .nav__icon { position: absolute; top: 0; right: -60px; padding: 20px; font-size: 20px; cursor: pointer; transition: color .3s; } .nav__icon:hover { color: #5eb2ff; } 

Repito, se a animação é relativamente simples, esse método é o principal. Os usuários apreciarão o desempenho do navegador.

ReactTransitionGroup


O componente ReactTransitionGroup foi desenvolvido pela equipe da comunidade ReactJS. Com ele, você pode implementar facilmente animações e transições básicas de CSS.

O ReactTransitionGroup foi projetado para alterar as classes ao alterar o ciclo de vida do componente. Ele tem um tamanho pequeno, precisa ser instalado no pacote para o aplicativo React, o que aumentará ligeiramente o tamanho geral da montagem. Além disso, você pode usar o CDN.

O ReactTransitionGroup possui três elementos: Transition, CSSTransition e TransitionGroup. Para iniciar a animação, você precisa agrupar o componente nelas. O estilo, por sua vez, precisa ser escrito nas classes CSS.

Aqui está a animação e, em seguida, a maneira de implementá-la.



A primeira etapa é importar o CSSTransitionGroup do grupo de transição de reação. Depois disso, você precisa agrupar a lista e definir a propriedade transitName. Sempre que você adiciona ou remove um filho em um CSSTransitionGroup, ele obtém estilos animados.

 <CSSTransitionGroup transitionName="example"> {items} </CSSTransitionGroup> 

Ao definir a propriedade transitName = "example", as classes nas folhas de estilo devem começar com o nome do exemplo.

 .example-enter { opacity: 0.01; } .example-enter.example-enter-active { opacity: 1; transition: opacity 300ms ease-in; } .example-leave { opacity: 1; } .example-leave.example-leave-active { opacity: 0.01; transition: opacity 300ms ease-in; 

Acima está um exemplo usando ReactTransitionGroup.

Você também precisa de lógica e dois métodos para implementar o exemplo de adição de uma lista de contatos.

O primeiro método handleAdd - adiciona novos contatos, obtém um nome aleatório, que depois coloca na matriz state.items.

Para remover um contato por índice na matriz state.items, use handleRemove.

 import React, { Component, Fragment } from 'react'; import { CSSTransitionGroup } from 'react-transition-group' import random from 'random-name' import Button from './button' import Item from './item' import './style.css'; export default class ReactTransitionGroup extends Component { constructor(props) { super(props); this.state = { items: ['Natividad Steen']}; this.handleAdd = this.handleAdd.bind(this); } handleAdd() { let newItems = this.state.items; newItems.push(random()); this.setState({ items: newItems }); } render () { const items = this.state.items.map((item, i) => ( <Item item={item} key={i} keyDelete={i} handleRemove={(i) => this.handleRemove(i)} /> )); return ( <Fragment> <Button onClick={this.handleAdd}/> <div className="project"> <CSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300} > {items} </CSSTransitionGroup> </div> </Fragment> ); } }; 

Reagir animações


React-animations é uma biblioteca criada em animate.css. É fácil trabalhar, ela tem muitas coleções de animação diferentes. A biblioteca é compatível com qualquer biblioteca de estilo embutido que suporte o uso de objetos para definir os principais quadros de uma animação, incluindo Radium, Afrodite ou componentes estilizados.



Eu sei o que você pensa:



Agora vamos ver como isso funciona com o exemplo de uma animação de rejeição.



Primeiro, importe a animação de react-animations.

const Bounce = styled.div`animation: 2s $ {quadros-chave` $ {bounce} `} infinito`;

Depois de criar o componente, envolvemos qualquer código HTML ou componente para animação.

 <bounce><h1>Hello Animation Bounce</h1></bounce> 

Um exemplo:

 import React, { Component } from 'react'; import styled, { keyframes } from 'styled-components'; import { bounce } from 'react-animations'; import './style.css'; const Bounce = styled.div`animation: 2s ${keyframes`${bounce}`} infinite`; export default class ReactAnimations extends Component { render() { return ( <Bounce><h1>Hello Animation Bounce</h1></bounce> ); } } 

Tudo funciona, a animação é muito simples. Além disso, há uma ótima solução para o uso de animação de salto ao rolar - reaja-animar-em-rolagem .

Reagir-revelar


A estrutura do React Reveal possui animações básicas, incluindo desbotamento, reflexão, redimensionamento, rotação e muito mais. Torna possível trabalhar com todas as animações usando adereços. Assim, você pode especificar configurações adicionais, incluindo posição, atraso, distância, cascata e outras. Outros efeitos CSS podem ser usados, incluindo renderização no servidor e componentes de alta ordem. Em geral, se você precisar de animação de rolagem, use essa estrutura.

 import Fade from 'react-reveal/Fade'; <Fade top> <h1>Title</h1> </Fade> 



Existem cinco blocos no total, cada um deles com uma página em tela cheia e um título.

 import React, { Component, Fragment } from 'react'; import Fade from 'react-reveal/Fade'; const animateList = [1, 2, 3, 4, 5]; export default class ReactReveal extends Component { render() { return ( <Fragment> {animateList.map((item, key) => ( <div style={styles.block} key={key}> <Fade top> <h1 style={styles.title}>{`block ${item}`}</h1> </Fade> </div> ))} </Fragment> ); } } const styles = { block: { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', background: '#000', borderBottom: '1px solid rgba(255,255,255,.2)', }, title: { textAlign: 'center', fontSize: 100, color: '#fff', fontFamily: 'Lato, sans-serif', fontWeight: 100, }, }; 

Agora, apresentamos a constante animateList. A matriz inclui cinco elementos. Depois de usar o método de matriz de mapa, é possível renderizar qualquer elemento nos componentes Fade inserindo elementos no cabeçalho. Os estilos definidos na constante de estilos recebem estilos CSS curtos para o bloco e o cabeçalho. Acima estão cinco blocos com animação Fade.

TweenOne e animação no Ant Design


O Ant Design é uma biblioteca do React UI que contém um grande número de componentes úteis e fáceis de usar. É adequado se você precisar criar interfaces de usuário elegantes. Desenvolvido pelo Alibaba, que usa a biblioteca em muitos de seus projetos.



O exemplo tem alguns componentes animados. A maioria deles tem animações semelhantes; portanto, um exemplo de implementação será mais simples que o acima. Isso incluirá apenas uma bola, uma bola verde e um elemento adicional, por exemplo, um quadrado vermelho.



A animação usa o componente TweenOne, que precisa do PathPlugin para definir corretamente a trajetória. Tudo isso funcionará apenas se colocado
PathPlugin em TweenOne.plugins.

 TweenOne.plugins.push(PathPlugin); 

As principais opções de animação são as seguintes:

  • duração - tempo de animação em ms;
  • facilidade - suavidade da animação;
  • ioiô - mudança de movimento para frente e para trás a cada repetição;
  • repeat - repita a animação. Você precisa usar -1 para animação sem fim;
  • p - as coordenadas do caminho para a animação;
  • easePath - coordenadas do caminho suave para animação.

Os dois últimos parâmetros são muito específicos, mas não se preocupe, tudo funciona como deveria.

 const duration = 7000; const ease = 'easeInOutSine'; const p = 'M123.5,89.5 C148,82.5 239.5,48.5 230,17.5 C220.5,-13.5 127,6 99.5,13.5 C72,21 -9.5,56.5 1.5,84.5 C12.5,112.5 99,96.5 123.5,89.5 Z'; const easePath = 'M0,100 C7.33333333,89 14.3333333,81.6666667 21,78 C25.3601456,75.6019199 29.8706084,72.9026327 33,70 C37.0478723,66.2454406 39.3980801,62.0758689 42.5,57 C48,46.5 61.5,32.5 70,28 C77.5,23.5 81.5,20 86.5,16 C89.8333333,13.3333333 94.3333333,8 100,0'; const loop = { yoyo: true, repeat: -1, duration, ease, }; 

Agora você pode começar a criar o objeto de animação.

  • O redSquare contém os parâmetros do loop, além da coordenada Y, duração e atraso.
  • greenBall contém o caminho com os parâmetros do objeto x, y - o valor de p. Além disso, duração, repetição e suavidade são uma função do TweenOne.easing.path, que possui dois parâmetros.
  • caminho - facilidade.
  • lengthPixel é uma curva dividida em apenas 400 seções.
  • pista - uma oval com eixos, possui estilos de ciclo e um parâmetro de rotação.

 const animate = { redSquare: { ...loop, y: 15, duration: 3000, delay: 200, }, greenBall: { path: { x: p, y: p }, duration: 5000, repeat: -1, ease: TweenOne.easing.path(easePath, { lengthPixel: 400 }), }, track: { ...loop, rotate: 15, }, }; 

Você também precisa prestar atenção ao componente TweenOne. Todos os componentes serão importados do rc-tween-one. O TweenOne é um componente básico com propriedades básicas e adereços animados, que são animações. Cada TweenOne possui seus próprios parâmetros de animação, como redSquare, track, greenBall.

 import React from 'react'; import TweenOne from 'rc-tween-one'; export default function BannerImage() { return ( <div className="wrapper-ant-design"> <svg width="482px" height="500px" viewBox="0 0 482 500"> <defs> <path d="M151,55 C129.666667,62.6666667 116,74.3333333 110,90 C104,105.666667 103,118.5 107,128.5 L225.5,96 C219.833333,79 209.666667,67 195,60 C180.333333,53 165.666667,51.3333333 151,55 L137,0 L306.5,6.5 L306.5,156 L227,187.5 L61.5,191 C4.5,175 -12.6666667,147.833333 10,109.5 C32.6666667,71.1666667 75,34.6666667 137,0 L151,55 Z" id="mask" /> </defs> <g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd" transform="translate(0, 30)"> <g id="Group-13" transform="translate(0.000000, 41.000000)"> <TweenOne component="g" animation={animate.redSquare}> <rect stroke="#F5222D" strokeWidth="1.6" transform="translate(184.000000, 18.000000) rotate(8.000000) translate(-184.000000, -18.000000) " x="176.8" y="150.8" width="14.4" height="14.4" rx="3.6" /> </TweenOne> </g> <g id="Group-14" transform="translate(150.000000, 230.000000)"> <g id="Group-22" transform="translate(62.000000, 7.000000)"> <image id="cc4" alt="globe" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/FpKOqFadwoFFIZFExjaf.png" width="151px" height="234px" /> </g> <mask id="mask-2"> <use xlinkHref="#mask" fill="white" transform="translate(-42, -33)" /> </mask> <g mask="url(#mask-2)"> <TweenOne component="g" animation={animate.track} style={{ transformOrigin: '122.7px 58px' }}> <g transform="translate(-16, -52)"> <g transform="translate(16, 52)"> <path d="M83.1700911,35.9320015 C63.5256194,37.9279025 44.419492,43.1766434 25.8517088,51.6782243 C14.3939956,57.7126276 7.77167019,64.8449292 7.77167019,72.4866248 C7.77167019,94.1920145 61.1993389,111.787709 127.105708,111.787709 C193.012078,111.787709 246.439746,94.1920145 246.439746,72.4866248 C246.439746,55.2822262 212.872939,40.6598106 166.13127,35.3351955" id="line-s" stroke="#0D1A26" strokeWidth="1.35" strokeLinecap="round" transform="translate(127.105708, 73.561453) rotate(-16.000000) translate(-127.105708, -73.561453) " /> </g> <TweenOne component="g" animation={animate.greenBall}> <image alt="globe" id="id2" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/IauKICnGjGnotJBEyCRK.png" x="16" y="62" width="26px" height="26px" /> </TweenOne> </g> </TweenOne> </g> </g> </g> </svg> </div> ); } 7.77167019,64.8449292 7.77167019,72.4866248 C7.77167019,94.1920145 61.1993389,111.787709 127.105708,111.787709 C193.012078,111.787709 246.439746,94.1920145 246,439746 import React from 'react'; import TweenOne from 'rc-tween-one'; export default function BannerImage() { return ( <div className="wrapper-ant-design"> <svg width="482px" height="500px" viewBox="0 0 482 500"> <defs> <path d="M151,55 C129.666667,62.6666667 116,74.3333333 110,90 C104,105.666667 103,118.5 107,128.5 L225.5,96 C219.833333,79 209.666667,67 195,60 C180.333333,53 165.666667,51.3333333 151,55 L137,0 L306.5,6.5 L306.5,156 L227,187.5 L61.5,191 C4.5,175 -12.6666667,147.833333 10,109.5 C32.6666667,71.1666667 75,34.6666667 137,0 L151,55 Z" id="mask" /> </defs> <g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd" transform="translate(0, 30)"> <g id="Group-13" transform="translate(0.000000, 41.000000)"> <TweenOne component="g" animation={animate.redSquare}> <rect stroke="#F5222D" strokeWidth="1.6" transform="translate(184.000000, 18.000000) rotate(8.000000) translate(-184.000000, -18.000000) " x="176.8" y="150.8" width="14.4" height="14.4" rx="3.6" /> </TweenOne> </g> <g id="Group-14" transform="translate(150.000000, 230.000000)"> <g id="Group-22" transform="translate(62.000000, 7.000000)"> <image id="cc4" alt="globe" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/FpKOqFadwoFFIZFExjaf.png" width="151px" height="234px" /> </g> <mask id="mask-2"> <use xlinkHref="#mask" fill="white" transform="translate(-42, -33)" /> </mask> <g mask="url(#mask-2)"> <TweenOne component="g" animation={animate.track} style={{ transformOrigin: '122.7px 58px' }}> <g transform="translate(-16, -52)"> <g transform="translate(16, 52)"> <path d="M83.1700911,35.9320015 C63.5256194,37.9279025 44.419492,43.1766434 25.8517088,51.6782243 C14.3939956,57.7126276 7.77167019,64.8449292 7.77167019,72.4866248 C7.77167019,94.1920145 61.1993389,111.787709 127.105708,111.787709 C193.012078,111.787709 246.439746,94.1920145 246.439746,72.4866248 C246.439746,55.2822262 212.872939,40.6598106 166.13127,35.3351955" id="line-s" stroke="#0D1A26" strokeWidth="1.35" strokeLinecap="round" transform="translate(127.105708, 73.561453) rotate(-16.000000) translate(-127.105708, -73.561453) " /> </g> <TweenOne component="g" animation={animate.greenBall}> <image alt="globe" id="id2" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/IauKICnGjGnotJBEyCRK.png" x="16" y="62" width="26px" height="26px" /> </TweenOne> </g> </TweenOne> </g> </g> </g> </svg> </div> ); } 



Sim, parece assustador, mas a animação usando esse método é simples.

  <TweenOne component="g" animation={animate.redSquare} /> <TweenOne component="g" animation={animate.track} /> <TweenOne component="g" animation={animate.greenBall} /> 

Tudo o que você precisa fazer é descrever as regras de animação e transferi-las para o componente TweenOne.

Para atingir objetivos diferentes, são necessárias abordagens diferentes. Este artigo examinou várias soluções que podem ser usadas em um grande número de projetos. Seu negócio é escolher o caminho certo.
A Skillbox recomenda:

Source: https://habr.com/ru/post/pt456972/


All Articles