Запустить анимацию CSS, когда элемент будет виден с Material-UI - PullRequest
0 голосов
/ 13 января 2020

Я провел некоторое исследование о том, как вызвать CSS анимацию, когда элемент появится в поле зрения, и нашел ответ , в котором используются IntersectionObserver и element.classList.add ('. Some-class-name')

Вышеописанный метод демонстрируется в чистом CSS, но я хочу реализовать его с помощью Material-UI. Вот мой код.

import React, { useEffect } from 'react';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles((theme) => ({
  root: {
    height: '100vh'
  },
  box: {
    opacity: 0,
    width: 100,
    height: 100,
    backgroundColor: 'red'
  },
  animated: {
    animationName: '$fadein',
    animationDuration: '1s'
  },
  '@keyframes fadein': {
    '0%': {
      opacity: 0
    },
    '100%': {
      opacity: 1
    }
  },
}));

function App() {
  const classes = useStyles();
  
  useEffect(() => {
    const observer = new IntersectionObserver((entries, observer) => {
      entries.forEach((entry) => {
        if (entry.intersectionRatio > 0) {

          // trigger animation
          entry.target.classList.add('animated');

          // remove observer
          observer.unobserve(entry.target);
        }
      });
    });

    const element = document.getElementById('item');
    observer.observe(element);      
  }, []);
  
  return (
    <div>
      <div className={classes.root} />
      <div id="item" className={classes.box} />
    </div>
  );
};

export default App;

К сожалению, приведенный выше код не работает, и я думаю, что это потому, что className 'animated' не существует. Я знаю, что Material-UI имеет внутренний лог c, который генерирует уникальное className, поэтому мой вопрос: как мне определить настоящее className «анимированного»? Или есть лучший способ go по этому поводу? Любая помощь будет оценена.

1 Ответ

1 голос
/ 14 января 2020

Это то, что я придумал.

import React, { useEffect, useState, useRef } from 'react';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles((theme) => ({
  root: {
    height: '100vh'
  },
  box: {
    opacity: 0,
    width: 100,
    height: 100,
    backgroundColor: 'red'
  },
  animated: {
    animationName: '$fadein',
    animationDuration: '1s',
    animationFillMode: 'forwards'
  },
  '@keyframes fadein': {
    '0%': {
      opacity: 0
    },
    '100%': {
      opacity: 1
    }
  }
}));

function App() {
  const classes = useStyles();

  const BoxSection = (props) => {
    const [isVisible, setVisible] = useState(false);
    const domRef = useRef();
    useEffect(() => {
      const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => setVisible(entry.isIntersecting));
      });
      observer.observe(domRef.current);
      return () => observer.unobserve(domRef.current);  // clean up
    }, []);
    return (
      <div className={`${classes.box} ${isVisible ? classes.animated : ''}`} ref={domRef}>
        {props.children}
      </div>
    );
  };

  return (
    <div>
      <div className={classes.root} />
      <BoxSection />
    </div>
  );
}

export default App;

По сути, я решил использовать состояние для запуска анимации, добавив класс, как описано выше. У меня есть несколько указателей из этой статьи , если кому-то интересно.

...