Управление поведением скролла

Vue Router предоставляет мощный инструмент для управления навигацией в одностраничных приложениях (SPA), включая контроль поведения скролла при переходах между маршрутами. Это позволяет создавать более естественный опыт для пользователей, особенно при работе с длинными страницами или при возврате к ранее посещённым позициям на странице.

Опция scrollBehavior

Основной механизм управления скроллом задаётся через опцию scrollBehavior в конфигурации роутера. Эта функция принимает три аргумента:

const router = VueRouter.createRouter({
  history: VueRouter.createWebHistory(),
  routes: [
    // маршруты приложения
  ],
  scrollBehavior(to, from, savedPosition) {
    // логика скролла
  }
})
  • to – объект маршрута, на который выполняется переход. Содержит информацию о целевом маршруте, включая путь, имя и параметры.
  • from – объект маршрута, с которого происходит переход.
  • savedPosition – объект с координатами скролла, если пользователь использует кнопки «назад» или «вперед» в браузере.

Возвращаемое значение функции scrollBehavior определяет позицию скролла:

  • { x: number, y: number } – координаты скролла относительно верхнего левого угла страницы.
  • false – оставляет текущую позицию скролла без изменений.
  • { selector: string } – прокрутка к элементу, выбранному с помощью CSS-селектора. Работает асинхронно с использованием querySelector.

Простейший пример

scrollBehavior(to, from, savedPosition) {
  if (savedPosition) {
    return savedPosition; // возвращаем пользователя на предыдущую позицию
  } else {
    return { x: 0, y: 0 }; // прокручиваем на верх страницы при переходе на новый маршрут
  }
}

В этом примере пользователь будет автоматически возвращаться к предыдущей позиции при навигации через кнопки браузера, а при обычном переходе скролл перемещается в верх страницы.

Прокрутка к элементам по якорю

Vue Router поддерживает навигацию к элементам с помощью якорей. Для этого используется свойство hash объекта маршрута и селектор в scrollBehavior:

scrollBehavior(to, from, savedPosition) {
  if (to.hash) {
    return { el: to.hash, beh * avior: 'smooth' }; // плавная прокрутка к элементу
  }
  return { x: 0, y: 0 };
}
  • el – элемент DOM, к которому будет выполнена прокрутка (например, #section1).
  • behavior – задаёт тип прокрутки: auto (по умолчанию) или smooth для плавного скролла.

Асинхронная обработка скролла

Иногда нужно дождаться загрузки данных перед прокруткой. Vue Router поддерживает асинхронное возвращение позиции скролла через Promise:

scrollBehavior(to, from, savedPosition) {
  return new Promise((resolve) => {
    setTimeout(() => {
      if (to.hash) {
        resolve({ el: to.hash, beh * avior: 'smooth' });
      } else if (savedPosition) {
        resolve(savedPosition);
      } else {
        resolve({ x: 0, y: 0 });
      }
    }, 300); // имитация задержки загрузки контента
  });
}

Это особенно полезно для страниц с динамически загружаемым контентом, когда элементы, к которым требуется прокрутка, ещё не созданы в DOM в момент навигации.

Контроль скролла на уровне маршрута

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

const routes = [
  {
    path: '/articles/:id',
    component: ArticlePage,
    meta: { scrollToTop: true }
  }
];

В функции scrollBehavior можно проверять это свойство:

scrollBehavior(to, from, savedPosition) {
  if (to.meta.scrollToTop) {
    return { x: 0, y: 0 };
  }
  return savedPosition || { x: 0, y: 0 };
}

Настройка поведения для вложенных маршрутов

При использовании вложенных маршрутов важно учитывать, что scrollBehavior вызывается только один раз за весь переход, независимо от количества вложенных компонентов. Поэтому логика должна учитывать все уровни маршрутов и их параметры, если требуется специфическая прокрутка:

scrollBehavior(to, from, savedPosition) {
  const nestedRoute = to.matched.find(record => record.meta.scrollToTop);
  if (nestedRoute) {
    return { x: 0, y: 0 };
  }
  return savedPosition || { x: 0, y: 0 };
}

Настройки плавного скролла для пользовательских компонентов

Для интеграции с пользовательскими компонентами и сторонними библиотеками можно использовать событие навигации afterEach:

router.afterEach((to, from) => {
  if (to.hash) {
    const element = document.querySelector(to.hash);
    if (element) {
      element.scrollIntoView({ beh * avior: 'smooth' });
    }
  }
});

Это даёт дополнительный контроль и возможность обрабатывать сложные сценарии, например, анимацию или отступы от фиксированных элементов.

Особенности и ограничения

  • scrollBehavior работает только в HTML5 History режиме (createWebHistory) или Hash режиме (createWebHashHistory).
  • При использовании el или selector Vue Router ждёт, пока элемент появится в DOM. Если элемент не найден, скролл остаётся на текущей позиции.
  • При возврате на предыдущую страницу savedPosition всегда имеет приоритет над другими правилами.

Управление скроллом через Vue Router обеспечивает гибкость и позволяет создавать удобный интерфейс навигации, минимизируя дискомфорт пользователя при перемещении по приложению. Правильная настройка scrollBehavior особенно критична для SPA с длинными страницами, контентом, загружаемым динамически, и навигацией с якорями.