@aic/react-scroll-top

React компонент высшего порядка для управления прокруткой при изменении адреса страницы с помощью react-router 4.x

Usage no npm install needed!

<script type="module">
  import aicReactScrollTop from 'https://cdn.skypack.dev/@aic/react-scroll-top';
</script>

README

scroll-top

React компонент высшего порядка для управления прокруткой при изменении адреса страницы с помощью react-router 4.x

Содержание

Описание

Данный компонент упрощает управление поведением прокрутки при изменении адреса страницы для разных частей вашего приложения.

Установка

npm

npm install --save-dev gitlab.aic.ru/Nikita_Torchinskiy/scroll-top.git

yarn

yarn add gitlab.aic.ru/Nikita_Torchinskiy/scroll-top.git

Использование

import scrollTop from 'scroll-top'

scrollTop(options)(AmazingReactComponent)

Параметры

Функция scrollTop принимает объект параметров options со следующими возможными полями:
(название: тип = значение по умолчанию)

  • scrollOnPathChanges: boolean = true - определяет, будет ли происходить прокрутка, когда меняется путь в адресе страницы. (/somePage => /otherPage)
  • scrollOnHashChanges: boolean = false - определяет, будет ли происходить прокрутка, когда меняется хэш в адресе страницы. (/somePage => /somePage#someHash)
  • scrollOnSearchChanges: boolean = false - определяет, будет ли происходить прокрутка, когда меняется поисковой запрос в адресе страницы. (/somePage => /somePage?param=value)
  • useOnMount: boolean = false - определяет, будет ли использоваться этот компонент сразу же, как только будет смонтирован react (переход со страницы без этого компонента на страницу с этим компонентом).
  • top: number = 0 - смещение от верха страницы (или элемента, если getComponentTop установлен в true) в пикселях, к которому будет происходить прокрутка.
  • getComponentTop: boolean = false - если определен как true, то позиция, к которой будет происходить прокрутка, будет определяться верней границей данного элемента на экране. При этом значение параметра top будет определять смещение от этой позиции.
  • scrollFunction: function (top: number): void = (top) => window.scrollTo(0, top) - функция, производящая прокрутку. Единственным параметром принимает top - отступ (в пикселях) от верха страницы, к которому должна производиться прокрутка. По умолчанию используется window.scrollTo(0, top).
  • checkLocation: function ({ location, match, prevLocation, prevMatch }): boolean
    = ({ match, prevMatch }) => match.url === prevMatch.url - функция, определяющая, должен ли данный компонент обрабатывать изменения в адресе страницы, или передать управление вышестоящему компоненту scrollTop (если имеется). Входной параметр - объект. location и match - текущие значения location и match из близжайшего Route; prevLocation и prevMatch - предыдущие значения соответственно. По умолчанию производится проверка match.url === prevMatch.url.

Если какой-то из параметров не указан, то для него будет использовано значение по умолчанию. Также options может быть типа boolean, тогда он будет использоваться как значение для scrollOnPathChanges.

Вложенность

Если на странице имеется одновременно несколько компонентов с scrollTop, то управлять прокруткой будет только самый глубокий по вложенности из них. Однако, если при изменении адреса страницы, для этого компонента проверка checkLocation вернет false, то управление перейдет к вышестоящему по вложенности компоненту.
Пример:

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router'

import scrollTop from 'scroll-top'
import App from './App'
import SomeComponent from './SomeComponent'

const AppWithScrollTop = scrollTop({
    scrollOnPathChanges: true
})(App)

const UserPageWithScrollTop = scrollTop({
    scrollOnPathChanges: false,
    
})(UserPage)

ReactDOM.render(
    <BrowserRouter>
        <AppWithScrollTop>
            <Switch>
                <Route path='/user/:id'>
                    <UserPageWithScrollTop />
                </Route>
                {/* ... */}
            </Switch>
        </AppWithScrollTop>
    </BrowserRouter>,
    document.getElementById('root')
)

В данном примере, нам необходимо, чтобы внутри App происходила прокрутка при переходе по страницам, однако, внутри UserPage - наоборот, т.к. там есть вкладки с информацией, которые переключаются при изменении адреса страницы.
Рассмотрим переход по страницам данного примера:

  1. Когда пользователь в браузере перейдет по пути /, ничего не произойдет, т.к. изменения в пути не происходило.
  2. Переход по ссылке на /about вызовет прокрутку к началу страницы.
  3. Переход по ссылке на /user/1 вызовет прокрутку. В параметрах компонента UserPageWithScrollTop прокрутка при изменении пути отключена, однако, по умолчанию, useOnMount = false, и прокруткой управляет компонент UserPageWithScrollTop.
    Если необходимо на данном этапе успользовать данный scrollTop для определения прокрутки, необходимо для компонента UserPageWithScrollTop установить параметр useOnMount в true.
  4. Переход по ссылке на /user/2 вызовет прокрутку, т.к. функция по умолчанию checkLocation вернула false. В данном случае match.url = /user/2, а prevMatch.url = /user/1. По этому управление передалось вышестоящему компоненту - AppWithScrollTop - для которого прокрутка включена.
    Если для данного этапа (изменение параметров Route) не нужно передавать управление вышестоящему компоненту, необходимо установить параметр checkLocation как () => true (или установить другую проверку, которая подходит).
  5. Переход по ссылке /user/2/some-info не вызовет прокрутки. Функция по умолчанию checkLocation возвращает true (match.url = prevMatch.url = /user/2), в параметрах прокрутка отключена.
  6. Переход по ссылке / вызовет прокрутку - компонента UserPageWithScrollTop уже нет на странице.

Процесс при изменении адреса

Что происходит, когда меняется адрес страницы?

  1. Определяется самый глубокий по дереву компонент с scrollTop.

  2. Если этот компонент был смонтирован только что, проверяется, что параметр useOnMount === true. Иначе управление передается близжайшему следующему компоненту scrollTop выше по дереву, и процесс начинается с этого шага (или заканчивается, если выше компонента нет).

  3. Происходит проверка - вызывается checkLocation из параметров этого компонента или заданный по умолчанию. Если проверка вернула false, управление передается близжайшему следующему компоненту scrollTop выше по дереву, и процесс начинается с шага 2. (или заканчивается, если выше компонента нет).

  4. Компонент, дошедший до этой стадии, проверяет следующие утверждения:

    • scrollOnPathChanges === true и изменился путь в адресе
    • scrollOnHashChanges === true и изменился хэш в адресе
    • scrollOnSearchChanges === true и изменился поисковой запрос в адресе

    Если хотя-бы одно из этих утверждений верно, происходит прокрутка страницы. Иначе процесс заканчивается.

Особенности

  • При первой загрузке страницы (или обновления) "процесс при изменении адреса" не запускается, и прокрутки никогда не происходит.
  • Если компонент был смонтирован только что, то в процессе изменения адреса в аргументах проверочной функции checkLocation предыдущие и текущие значения будут равны (prevMatch === match, prevLocation === location).
  • Не используйте компоненты с scrollTop не вложенными друг в друга в дереве - иначе работать будет только один из них.