Хвильовий ефект в React

  • 30 апреля, 14:33
  • 4841
  • 0

Багато з нас бачили  анімацію хвильового ефекту, яка була частиною Material Design. Хвиля являє собою коло, яке з'являється в точці клацання, а потім збільшується і зникає. Як інструмент для користувача інтерфейсу, це знайомий спосіб повідомити користувачеві, що сталося клацання.

В React найпростіший спосіб - використовувати  Material-UI, який є популярною UI бібліотекою. Загалом, це дуже хороша ідея, якщо тобі потрібна солідна UI бібліотека, яка генерує UI з коробки. Однак, для невеликого проекту не має сенсу вчитися працювати з великою бібліотекою тільки для досягнення одного ефекту.

Хвильовий ефект в React

Я переглянув безліч проектів, що реалізують щось подібне в Github, Codepen і Codesandbox, і черпав натхнення в деяких з кращих. Хвильовий можливий на будь-який веб-платформі, так як він досягається за допомогою CSS.

Ось як виглядає моя імплементація CSS.

<button class = "button" >    <div class = "ripple-container" >      <span class = "ripple" > </ span>    </ Div> </ Button>

.button {   overflow : hidden ;   position : relative ; } .ripple-container {   top : 0 ;    left : 0 ;    right : 0 ;    bottom : 0 ;    z-index : 0 ;    overflow : hidden ;   position : absolute ; } .ripple-container span {   position : absolute ;   top : . . . ;    left : . . . ;    height : . . . ;    width : . . . ;    transform : scale ( 0 ) ;   border-radius : 100% ;    opacity : 0. 25 ;    background-color : #fff ;    animation-name : ripple ;   animation-duration : 850ms ;  } @keyframes ripple {   to {     opacity : 0 ;      transform : scale ( 2 ) ;   } }

Властивість  overflow: hidden запобігає виходу хвилі з контейнера. Брижі (хвилі) - це коло ( border-radius: 100% ), яке починається з невеликого розміру і стає більше по мірі зникнення. Зростаюча і зникає анімація досягається шляхом маніпулювання  transform: scale  і  opacity .

Однак, нам потрібно буде динамічно надати кілька стилів з використанням Javascript. Знайти позиційні координати: тобто  top і  left, які засновані на тому, де користувач клацнув, а також  height і  width, які залежать від розміру контейнера.

Почнемо

Для своїх стилів мені зручно використовувати стильові компоненти. Ти ж можеш використовувати те, що вважаєш за краще. Перше, що ми зробимо - додамо вищевказаний CSS в наші компоненти. Стилі будуть знаходитися в окремому файлі.

// file => styles.ts import styled from "styled-components" ; export const Button = styled . button `    position : relative ;   padding : 5px 30px ;   overflow : hidden ;   cursor : pointer ;   background - color : $ { ( props ) = > ( props . color ? props . color : "tomato" ) } ;        color : #fff ;   font - size : 20px ;   border - radius : 20px ;   border : 1px solid #fff ;   text - align : center ;   box - shadow : 0 0 5px rgba ( 0 , 0 , 0 , 0.4 ) ;        box - sizing : border - box ; ` ; export const RippleContainer = styled . div `    top : 0 ;    left : 0 ;    right : 0 ;    bottom : 0 ;    z - index : 0 ;    overflow : hidden ;   position : absolute ;   border - radius : inherit ;   span {     position : absolute ;     transform : scale ( 0 ) ;     border - radius : 100 % ;      opacity : 0.25 ;      background - color : $ { ( props ) = > props . color } ;      animation - name : ripple ;     animation - duration : $ { ( props ) = > props . duration } ms ;    }   @ Keyframes ripple {     to {       opacity : 0 ;        transform : scale ( 2 ) ;     }   } ` ;

Зверни увагу, що для кнопки  background-color залежить від  props color  самого стильового компонента, але якщо він не буде переданий, то за замовчуванням буде фон  tomato. Для контейнера теж саме. Плюс тривалість анімації залежить від  props . Це зроблено для того, щоб ми могли динамічно встановлювати ці значення пізніше. Давай визначимо їх зараз:

import React from 'react' . . . export function Ripple ( { duration = 850 , color = "#ffffff" } ) {        . . . }

Далі для нашої брижі ми визначаємо масив і створюємо функцію для додавання мерехтіння в цей масив. Кожен елемент масиву буде об'єктом з властивостями  x,  y і  size, які є інформацією, необхідною для стилізації хвилі. Щоб обчислити ці значення, ми винесемо їх з події  mousedown.

export function Ripple ( { duration = 850 , color = '#ffffff' } ) {        const [ rippleArray , setRippleArray ] = React . useState ( [ ] ) ;     const addRipple = ( event ) = > {        // Координати контейнера     const rippleContainer = event . currentTarget . getBoundingClientRect ( ) ;     // Вибираємо найдовшу сторону     const size =       rippleContainer . width > rippleContainer . height          ? rippleContainer . width         : RippleContainer . height ;     // Координати клацання миші     const x = event . pageX - rippleContainer . left - size / 2 ;        const y = event . pageY - rippleContainer . top - size / 2 ;        // Нова хвиля     const newRipple = {        x ,       y ,       size     } ;     setRippleArray ( [ . . . rippleArray , newRipple ] ) ;   } ;   return (      . . .   ) ; }

Наведений вище код використовує API браузера  getBoundClientRect(), який дозволяє нам отримати найдовший край контейнера і координати  x (left) і  y (top), щодо документа. Разом з  MouseEvent.pageX і  MouseEvent.pageY він дозволяє нам обчислювати координати  x і  y миші (клацання) щодо контейнера. 

Тепер можемо візуалізувати масив хвилі (брижі).

return (    < RippleContainer duration = { duration } color = { color } onMouseDown = { addRipple } >     { RippleArray . length & &        rippleArray . map ( ( ripple , index ) = > {           return (            < span             key = { "span" + index }              style = { {               top : ripple . y ,               left : ripple . x ,               width : ripple . size ,               height : ripple . size ,             } }           / >         ) ;       } ) }   < / RippleContainer > ) ;

RippleContainer  - це стилізований компонент, який приймає  duration і  color як  props, разом з  addRipple в якості обробника події  onMouseDown. Усередині нього ми відображаємо всі наші хвилі і додаємо розраховані параметри  top, left, width  і  height .

З цим ми закінчили. Тим не менш, є ще одна маленька річ, яку потрібно зробити, а саме: очистити брижі після того, як вони зробили анімацію. Це зроблено для того, щоб застарілі елементи не захаращували DOM.

Нижче приведена реалізація і використання  useEffect хука. По суті, кожен раз, коли ми створюємо нову хвилю, таймер скидається. Зверни увагу, що тривалість тайм-ауту набагато більше, ніж наша брижа.

React . useEffect ( ( ) = > {     let bounce ;   if ( rippleArray . length > 0 ) {         window . clearTimeout ( bounce ) ;     bounce = window . setTimeout ( ( ) = > {         setRippleArray ( [ ] ) ;       window . clearTimeout ( bounce ) ;     } , Duration * 4 ) ;    }   return ( ) = > window . clearTimeout ( bounce ) ;   } , [ RippleArray . length , duration ] ) ; 

Тепер ми закінчили з нашим компонентом Ripple. Давай створимо кнопки.

import React from "react" ; import "./App.css" ; import { Ripple } from "./RippleButton" ; import { Button } from "./RippleButton/styles" ; function App ( ) {    return (      <div className = "App" >       <header className = "App-header" >         <Button>           Learn React           <Ripple duration = { 850 } color = "#fff" />         </ Button>         <Button>           Learn React           <Ripple duration = { 1000 } color = "#fff" />         </ Button>         <Button>           Learn React           <Ripple duration = { 2000 } color = "#fff" />         </ Button>       </ Header>     </ Div>   ) ; } export default App;

Тепер у нас є брижі у всіх відтінках і швидкостях. Більш того, наш компонент  Ripple, якщо він має  overflow: hidden і  position: relative в своїх стилях, може бути повторно використаний практично в будь-якому контейнері.

Джерело перекладу


0 комментариев
Сортировка:
Добавить комментарий

IT Новости

Смотреть все