Асинхронная прокрутка

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

Настройка поведения прокрутки

Для включения кастомного управления прокруткой используется опция scrollBehavior при создании экземпляра маршрутизатора:

import { createRouter, createWebHistory } from 'vue-router';
import Home from './views/Home.vue';
import About from './views/About.vue';

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
  scrollBehavior(to, from, savedPosition) {
    // Логика прокрутки будет рассмотрена ниже
  }
});

export default router;

Функция scrollBehavior принимает три аргумента:

  • to — объект маршрута, на который осуществляется переход;
  • from — объект маршрута, с которого происходит переход;
  • savedPosition — объект позиции скролла, если используется кнопка “назад/вперед” браузера.

Возвращаемое значение функции определяет позицию скролла. Можно вернуть объект вида { left: 0, top: 0 } для установки скролла в верхнюю часть страницы.

Асинхронная логика

В стандартной реализации scrollBehavior возвращает позицию синхронно. Однако иногда необходимо дождаться загрузки асинхронных данных или рендеринга компонента перед прокруткой. Для этого scrollBehavior может возвращать промис:

scrollBehavior(to, from, savedPosition) {
  return new Promise((resolve) => {
    setTimeout(() => {
      if (savedPosition) {
        resolve(savedPosition);
      } else {
        resolve({ left: 0, top: 0 });
      }
    }, 300);
  });
}

В этом примере прокрутка выполняется с задержкой 300 мс, что имитирует ожидание асинхронной загрузки данных. После завершения промиса Vue Router перемещает скролл на указанную позицию.

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

Асинхронная прокрутка особенно полезна при навигации к якорным ссылкам. Если компонент еще не смонтирован, позицию элемента невозможно вычислить сразу. Использование промиса позволяет дождаться полной загрузки DOM:

scrollBehavior(to, from, savedPosition) {
  return new Promise((resolve) => {
    const waitForElement = () => {
      const element = document.querySelector(to.hash);
      if (element) {
        resolve({ el: to.hash });
      } else {
        requestAnimationFrame(waitForElement);
      }
    };
    waitForElement();
  });
}

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

Совмещение с сохраненной позицией

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

scrollBehavior(to, from, savedPosition) {
  return new Promise((resolve) => {
    const handleScroll = () => {
      if (savedPosition) {
        resolve(savedPosition);
      } else if (to.hash) {
        const el = document.querySelector(to.hash);
        if (el) {
          resolve({ el: to.hash, beh * avior: 'smooth' });
        } else {
          requestAnimationFrame(handleScroll);
        }
      } else {
        resolve({ left: 0, top: 0 });
      }
    };
    handleScroll();
  });
}

Плавная прокрутка

Vue Router позволяет использовать стандартное свойство beh * avior: 'smooth', чтобы переход выглядел естественно. Это особенно удобно для длинных страниц с якорными ссылками:

resolve({ el: to.hash, beh * avior: 'smooth' });

В комбинации с асинхронной проверкой DOM это обеспечивает корректную и плавную прокрутку даже при медленной загрузке компонентов или динамически генерируемого контента.

Рекомендации по использованию

  • Использовать промисы в scrollBehavior при асинхронной загрузке данных или компонентов.
  • Всегда проверять наличие якорного элемента перед прокруткой.
  • Для SPA, где часто обновляется DOM, использовать requestAnimationFrame для циклической проверки элемента.
  • Комбинировать с сохранением позиции (savedPosition) для поддержки навигации браузера.
  • Применять beh * avior: 'smooth' для улучшения UX при переходах к якорям.

Асинхронная прокрутка делает навигацию в Vue Router гибкой и позволяет управлять положением скролла в зависимости от состояния приложения, асинхронной загрузки данных и особенностей рендеринга компонентов.