简体   繁体   中英

Changing content based on scroll position

I am trying to build a Showcase component, similar to the one seen here , where the user cycles through different content as they scroll:

在此处输入图像描述

I'm making the section fixed by using some CSS:

.sticky {
  position: sticky;
}

.top-0 {
  top: 0;
}

Applied to my HTML:

  <section
    ref={(r) => this.ref = r}
    className={`vh-500 bg-near-white z-max pv6-ns pv3 bg-near-white min-vh-100
    ...
    `}>
    <div className='sticky top-0 vh-100'>

Using the ref on my HTML element, I work out the area where the Showcase component is sticky by seeing the scrollY is relation to the top and bottom of the component itself:

  componentDidMount() {
    if (this.ref) {
      this.setState(
        {
          firstThreshold: this.ref.getBoundingClientRect().top,
          secondThreshold: window.innerHeight * amount
        },
        // tslint:disable-next-line:no-console
        () => console.log(this.state, "state")
      );
    }
    window.addEventListener("scroll", this.handleScroll);
  }

Then in my handleScroll() function I detect when we're scrolling through the Showcase component:

// if we're scrolling through the Showcase component
if (scrollY >= firstThreshold && scrollY <= secondThreshold) {
...
}

Now here's the bit I'm lost with:

I get the height of the Component by multiplying the viewport height with the amount of chapters of a story I want to display in my component:

const chapters = [
  {
    content: 'Signs up',
    title: '',
  },
  {
    content: 'Receives request',
    title: '',
  },
  {
    content: 'Gets a shit, rude requests from a person with 0 rating',
    title: '',
  },
  {
    content: 'Blocks them',
    title: '',
  },
  {
    content: 'Gets a nice request from a person who’s rated 5 stars',
    title: '',
  },
  {
    content: 'They agree on terms and accept the request',
    title: '',
  },
  {
    content: 'Time elapses',
    title: '',
  },
  {
    content: 'Thanks them for the time, gives them 5 stars',
    title: '',
  },
]

const amount = chapters.length

And in my handleScroll() function I'm trying to work out which chapter to show as the user scrolls, but I'm not sure how to get there. Here's what I have right now:

  for (let i = 0; i < amount; i++) {
    // tslint:disable-next-line:no-console
    console.log(i, "i");
    if (scrollY >= (firstThreshold + sectionThreshold) * i) {
      // tslint:disable-next-line:no-console
      console.log(sectionThreshold * i, "sectionThreshold * i");
      this.setState({ currentChapter: i }, () => {
        // tslint:disable-next-line:no-console
        console.log(
          `scrolling inside section: ${this.state.currentChapter}`
        );
      });
    }
  }

What I am trying to achieve:

  • Display each chapter as the user scrolls through the page

How do I do this?

Codesandbox

So I managed to figure it out, I think I was just overthinking it before. Basically inside of the handleScroll(e) you get the height of each section:

First, get the height of the chapters by dividing the chapterAmount by the componentHeight and push the results into an array:

const chapterHeights = [];
for (let index = 0; index < chapters.length; index++) {
  const chapterHeight = componentHeight / chapterAmount;
  chapterHeights.push(chapterHeight * index);
}

Then loop through chapterHeights array and compare it to the scroll position, then set the state of the title and content which will be rendered in the view.

for (let index = 0; index < chapterHeights.length; index++) {
  // console.log(chapterHeights[index], "chapterHeights[index]");
  const chapterLength = chapterHeights[index];

  if (scrollY >= chapterLength) {
    this.setState({
      title: chapters[index].title,
      content: chapters[index].content,
    })
  }
}

Codesandbox here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM