Реплицирующий переход на основе пересечения наблюдателя - PullRequest
1 голос
/ 26 марта 2019

Я работал над сайд-проектом, где меня попросили создать сайт с анимацией вокруг него. Я решил начать с React (чтобы изучить новую структуру и расширить свои знания).

Одна важная анимация, которую я отслеживаю (или пытаюсь воспроизвести), взята с сайта Apple .

Когда вы запускаете веб-страницу и прокручиваете ее вниз, текст отображается плавно, переместившись на 60 пикселей и изменив прозрачность. Как только он находится в окне просмотра.

Я пытался сделать это с классами. Тем не менее, у меня возникли бы проблемы с классами, так как они иногда повторно отображали бы мой элемент, или компонент не был бы виден при обновлении.

Я также пытался использовать fadeIn с setInterval, однако каждый раз, когда он активируется, он работает по-разному.

Мой компонент, который использует анимацию:


import React, { Component } from "react";
import "./SuccessStory.css";

class SuccessStory extends Component {
  state = {
    componentAppearsScrollUp: false,
    componentDisappearsScrollUp: false,
    componentAppearsScrollDown: false,
    componentDisappearsScrollDown: false,
    showComponent: false,
    translateMove: 60,
    opacity: 0
  };

  fadingIn() {
    const timer = setInterval(() => {
      if (this.state.opacity >= 1) {
        clearInterval(timer);
        return;
      }
      this.setState({
        opacity: this.state.opacity + 0.05
      });
    }, 100);
  }

  fadingOut() {
    const timer = setInterval(() => {
      if (this.state.opacity <= 0) {
        clearInterval(timer);
      }
      this.setState({
        opacity: this.state.opacity - 0.05
      });
    }, 100);
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.props.currentY < prevProps.currentY) {
      if (
        this.props.intersectionRatio > prevProps.intersectionRatio &&
        this.props.isIntersecting
      ) {
        if (this.props.intersectionRatio > 0.6) {
          console.log("Scrolling down enter");
          this.fadingIn();
          this.setState({
            componentAppearsScrollUp: false,
            componentDisappearsScrollUp: false,
            componentAppearsScrollDown: true,
            componentDisappearsScrollDown: false,
            showComponent: true
          });
        }
      } else {
        if (
          this.props.intersectionRatio < 0.8 &&
          this.props.intersectionRatio > 0.6
        ) {
          console.log("Scrolling down leave");
          this.setState({
            componentAppearsScrollUp: false,
            componentDisappearsScrollUp: false,
            componentAppearsScrollDown: false,
            componentDisappearsScrollDown: true,
            showComponent: true
          });
          this.fadingOut();
        }
      }
    } else if (
      this.props.currentY > prevProps.currentY &&
      this.props.isIntersecting
    ) {
      if (this.props.intersectionRatio < prevProps.intersectionRatio) {
        if (this.props.intersectionRatio < 0.9) {
          console.log("Scrolling up leave");
          this.fadingOut();
          this.setState({
            componentAppearsScrollUp: false,
            componentDisappearsScrollUp: true,
            componentAppearsScrollDown: false,
            componentDisappearsScrollDown: false,
            showComponent: true
          });
        }
      } else {
        if (
          this.props.intersectionRatio > 0.6 &&
          this.props.intersectionRatio < 0.8
        ) {
          console.log("Scrolling up enter");
          this.setState({
            componentAppearsScrollUp: true,
            componentDisappearsScrollUp: false,
            componentAppearsScrollDown: false,
            componentDisappearsScrollDown: false,
            showComponent: true
          });
          this.fadingIn();
        }
      }
    } else if (
      this.props.isIntersecting &&
      this.props.intersectionRatio > 0.9
    ) {
      this.fadingIn();
    }
  }

  render() {
    return (
      <div
        className={
          (this.state.componentAppearsScrollDown
            ? " story-appear-scroll-down "
            : "") +
          (this.state.componentDisappearsScrollDown
            ? " story-disappear-scroll-down "
            : "") +
          (this.state.componentAppearsScrollUp
            ? "story-appear-scroll-up "
            : "") +
          (this.state.componentDisappearsScrollUp
            ? " story-disappear-scroll-up "
            : "")
        }
        style={{
          opacity: this.state.opacity
        }}
      >
        <h1 className="success-story">The success story</h1>
        <h2
          className="success-story-text-one"
          // style={
          //   this.props.isIntersecting && this.props.intersectionRatio > 0.8
          //     ? { opacity: 1 }
          //     : { opacity: 0 }
          // }
        >
          MobileLife brought together over 100 dedicated people based in
          Copenhagen and Vilnius to deliver innovative mobile solutions to the
          banking customers in Nordic markets.
        </h2>
      </div>
    );
  }
}

export default SuccessStory;

Мой родительский компонент, который передает значения наблюдателя пересечения дочернему компоненту:


import React, { Component } from "react";
import "./SecondPage.css";
import SuccessStory from "./SuccessStory";
import { InView } from "react-intersection-observer";
// import SuccessStoryText1 from "./SuccessStoryText1";
import SuccessStoryText2 from "./SuccessStoryText2";

class SecondPage extends Component {
  state = {
    isIntersecting: false,
    intersectionRatio: "",
    currentY: "",
    isIntersectingSecondText: false,
    intersectionRatioSecondText: "",
    currentYSecondText: ""
  };

  render() {
    return (
      <div className="second-page">
        <div className="navigation-second" style={{ position: "sticky" }} />
        <div style={{ paddingTop: "25%", height: "60vh" }}>
          <InView
            threshold={[0.1, 0.2, 0.3, 0.4, 0.6, 0.75, 0.8]}
            onChange={(inView, ref) => {
              this.setState({
                currentY: ref.boundingClientRect.y,
                isIntersecting: ref.isIntersecting,
                intersectionRatio: ref.intersectionRatio
              });

              // console.log("Inview:", inView, ref);
            }}
          >
            {({ inView, ref }) => (
              <div ref={ref} style={{ position: "sticky", top: "30%" }}>
                <SuccessStory
                  isIntersecting={this.state.isIntersecting}
                  intersectionRatio={this.state.intersectionRatio}
                  currentY={this.state.currentY}
                />
              </div>
            )}
          </InView>
        </div>

        <InView
          threshold={[0.1, 0.2, 0.3, 0.4, 0.6, 0.75, 0.8]}
          onChange={(inView, ref) => {
            if (ref.intersectionRatio > 0.1) {
              this.setState({
                currentYSecondText: ref.boundingClientRect.y,
                isIntersectingSecondText: ref.isIntersecting,
                intersectionRatioSecondText: ref.intersectionRatio
              });
            }
            // console.log("Inview:", inView, ref);
          }}
        >
          {({ inView, ref }) => (
            <div ref={ref}>
              <SuccessStoryText2
                isIntersecting={this.state.isIntersectingSecondText}
                intersectionRatio={this.state.intersectionRatioSecondText}
                currentY={this.state.currentYSecondText}
              />
            </div>
          )}
        </InView>
      </div>
    );
  }
}
//
export default SecondPage;


А вот Css, который я использую для анимации:

.story-appear-scroll-down {
  animation: successStoryTextAppearScrollDown 0.3s linear;
  animation-fill-mode: forwards;
}

@keyframes successStoryTextAppearScrollDown {
  from {
    transform: translate3d(0, 60px, 0);
  }
  to {
    transform: translate3d(0, 0, 0);
  }
}

.story-disappear-scroll-down {
  animation: successStoryTextDisappearScrollDown 0.3s linear;
  animation-fill-mode: forwards;
}

@keyframes successStoryTextDisappearScrollDown {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(0, 0, 0);
  }
}

.story-appear-scroll-up {
  animation: successStoryTextAppearScrollUp 0.3s linear;
  animation-fill-mode: forwards;
}

@keyframes successStoryTextAppearScrollUp {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(0, 0, 0);
  }
}

.story-disappear-scroll-up {
  animation: successStoryTextDisappearScrollUp 0.3s linear;
  animation-fill-mode: forwards;
}

@keyframes successStoryTextDisappearScrollUp {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(0, 60px, 0);
  }
}

Я думал, что будет правильным способом активировать такую ​​анимацию, которую я пытаюсь воспроизвести, и она будет выглядеть одинаково при каждой активации (как на веб-странице Apple). Однако, поскольку я уже потратил на это слишком много времени, я не могу получить желаемые результаты.

Я ценю вашу помощь, и любые советы или предложения приветствуются, так как это мой первый пост.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...