Проблема прокрутки наблюдателя пересечения на мобильных устройствах - PullRequest
0 голосов
/ 25 февраля 2020

У меня проблемы с наблюдателем на пересечении в Гэтсби js.

Существует фиксированный заголовок, который должен изменить цвет, когда какой-то раздел входит в 90% области просмотра.

Я создал компонент с именем IntersectionObserverComponent , который отображает div с абсолютной позицией и высотой 100vh. Идея состоит в том, чтобы включить этот компонент в раздел, который я хочу отслеживать с помощью Intersection Observer.

Вот мой компонент

class IntersectionObserverComponent extends React.PureComponent {
  constructor(props) {
    super(props)
    //
    this.observer = null
    this.ref = React.createRef()
  }

  componentDidMount() {
    const { root, threshold, callback } = this.props

    ('IntersectionObserver' in window
      ? Promise.resolve()
      : import('intersection-observer')
    ).then(() => {
      this.observer = new IntersectionObserver(
        entries => {
          entries.forEach(entry => {
            callback(entry)
          })
        },
        { threshold, root }
      )

      if (this.ref.current) {
        this.observer.POLL_INTERVAL = 100
        this.observer.observe(this.ref.current)
      }
    })
  }

  componentWillUnmount() {
    if (this.ref.current && this.observer) {
      this.observer.unobserve(this.ref.current)
    }
  }

  render() {
    return (
      <div
        ref={this.ref}
        style={{
          height: '100vh',
          position: 'absolute',
          top: 0,
          left: 0,
          right: 0,
        }}
      ></div>
    )
  }
}

export default IntersectionObserverComponent

А вот использование

import { handleHeaderStyle } from '../../utils/intersectionObserver'

const About = ({ isTrackable = false, handleChangeHeader = () => {} }) => {
  // previousValues object is directly mutated in a handleHeaderStyle fn
  const previousValues = { previousY: 0, previousRatio: 0 }
  const colors = { prevColor: 'white', currColor: 'secondary' }

  const handleIOCallback = entry => {
    console.log(entry)
    handleHeaderStyle(entry, colors, previousValues, handleChangeHeader)
  }

  return (
    <section className="padding-top-m padding-bottom-tablet-portrait-96 header-behind background-gray-small-only">
      {isTrackable ? <IO callback={handleIOCallback} /> : null}

      <Container>
        <Grid className="grid-padding-x">
          <Cell small={12} large={8}>
            <p className="margin-bottom-small-20 margin-bottom-tablet-portrait-32">
              We are a brand and product development consultancy, that believes
              in that design is essentially a problem-solving exercise that we
              can apply to any sector, discipline or media.
            </p>
            <p className="margin-bottom-small-32">
              We are founded on and by people who are driven by:
            </p>
            <ul className="arrow-bullets">
              <li>
                Crafting simple and notable components that build up your
                brand’s value
              </li>
              <li>Discovery and research aimed at thoughtful practices</li>
              <li>Attention to detail</li>
              <li>Independence and creative freedom</li>
              <li>Thinking that goes deeper</li>
            </ul>
          </Cell>
          <Cell className="padding-top-m">
            <Projects />
          </Cell>
        </Grid>
      </Container>
    </section>
  )
}

export default About

А вот функция, которая обрабатывает logi c для обновления заголовка

export const handleHeaderStyle = (
  IOEntry,
  colors,
  previousValues,
  callback
) => {
  if (!IOEntry || !colors || !previousValues || typeof callback !== 'function')
    return
  //
  const { prevColor, currColor } = colors
  const currentY = IOEntry.boundingClientRect.y
  const currentRatio = IOEntry.intersectionRatio
  const isIntersecting = IOEntry.isIntersecting

  // going up
  if (currentY > previousValues.previousY) {
    if (currentRatio < previousValues.previousRatio && !isIntersecting) {
      callback(prevColor)
    }
  }
  // going down
  else if (currentY < previousValues.previousY && isIntersecting) {
    if (currentRatio > previousValues.previousRatio) {
      callback(currColor)
    }
  }

  previousValues.previousY = currentY
  previousValues.previousRatio = currentRatio
}

Это работает очень хорошо на всех размерах экрана, когда я тестирую его в браузере настольного компьютера, но проблема возникает, когда я тестирую его на реальном мобильное устройство.

  • Устройство: Iphone 7+, IOS 13.3.1
  • Браузеры: Safari 12.1.1, Chrome 80

It отлично работает, если я не отпускаю палец во время прокрутки, но если я это сделаю, обратный вызов не срабатывает постоянно. Я также попытался установить POLL_INTERVAL на 100 мс, но это не помогло.

Я подозреваю, что это как-то связано с тем, как iOS Safari обрабатывает событие прокрутки (https://github.com/martinlaxenaire/curtainsjs/issues/18)

Вот тестовая ссылка на Netlify - https://nifty-einstein-c4cf08.netlify.com/

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

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