Angular 2 Scroll to top on Route Change: решение для начинающих

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Angular 2 Scroll to top on Route Change: почему это важно и как реализовать

Представьте, что вы листаете длинную страницу с документацией, доходите до середины, кликаете на ссылку — и оказываетесь внизу нового раздела. Знакомо? Именно эту проблему решает механика Angular 2 scroll to top on route change. Без неё пользовательский опыт страдает: приходится вручную крутить колёсико мыши или жать Home, что раздражает и увеличивает отказы.

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

Почему Angular не делает это "из коробки"?

Angular — мощный SPA-фреймворк, но его поведение при навигации может удивлять. По умолчанию при смене маршрута браузер не сбрасывает позицию скролла. Почему? Потому что Angular Router рассматривает переход как замену компонента в <router-outlet>, а не как загрузку новой страницы. Браузер же думает: «Я всё ещё на том же документе, зачем мне скроллиться?».

Это особенно заметно, если у вас есть длинные списки, таблицы или документация. Пользователь кликает по ссылке внизу страницы — и новый контент открывается, но скролл остаётся внизу. Решение этой проблемы — явно указать Angular: «Эй, при каждом переходе крути наверх!».

Два подхода к решению

Существует два основных способа реализовать scroll to top on route change в Angular 2+:

  • Глобальный обработчик в AppComponent — простой, но работает не всегда корректно с вложенными маршрутами.
  • Использование Route Config — более гибкий, позволяет настраивать поведение для каждого маршрута отдельно.

Мы рассмотрим оба, но рекомендую остановиться на втором — он даёт больше контроля.

Способ 1: Простой глобальный обработчик (для быстрого старта)

Откройте ваш app.component.ts (или корневой компонент) и добавьте подписку на события Router. Код на TypeScript:


import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  constructor(private router: Router) {}

  ngOnInit() {
    this.router.events.pipe(
      filter(event => event instanceof NavigationEnd)
    ).subscribe(() => {
      window.scrollTo(0, 0);
    });
  }
}

Здесь мы подписываемся на события роутера, фильтруем только NavigationEnd (момент, когда переход завершён), и вызываем window.scrollTo(0, 0). Просто, но есть нюанс: если у вас есть вложенные маршруты (например, дочерние роуты внутри компонента), этот код может срабатывать слишком рано или не срабатывать вовсе.

Способ 2: Правильное решение с использованием Route Config (рекомендуется)

Этот подход использует встроенную опцию scrollPositionRestoration в Angular Router. Начиная с Angular 6.1, появилась возможность настроить автоматическое восстановление/сброс скролла прямо в конфигурации маршрутизации.

Откройте ваш app-routing.module.ts и добавьте опцию scrollPositionRestoration: 'top' в RouterModule.forRoot():


import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent },
  { path: 'contact', component: ContactComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'top' // <-- вот это
  })],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Одна строчка — и все переходы будут автоматически скроллить к верху. Но будьте внимательны: если у вас есть маршруты, где скролл нужно сохранять (например, список с пагинацией), используйте scrollPositionRestoration: 'enabled' — он будет восстанавливать позицию при возврате назад.

Способ 3: Тонкая настройка с помощью Anchor Scrolling

Иногда нужно не просто скроллить наверх, а переходить к конкретному элементу на странице (например, #section1). Для этого используйте фрагменты URL (anchor links):


imports: [RouterModule.forRoot(routes, {
  anchorScrolling: 'enabled',
  scrollPositionRestoration: 'enabled'
})]

Теперь в шаблоне можно писать:


<a [routerLink]="['/page']" fragment="section1">Перейти к разделу 1</a>

Angular сам найдёт элемент с id="section1" и прокрутит к нему. Комбинация scrollPositionRestoration и anchorScrolling даёт полный контроль.

Что делать, если решение не работает?

Бывает, что код написан, а скролл всё равно не срабатывает. Проверьте три вещи:

  • Версия Angular: scrollPositionRestoration доступен с Angular 6.1. Если у вас старше — обновите или используйте первый способ.
  • Порядок импортов: убедитесь, что вы импортируете RouterModule.forRoot() именно в корневом модуле, а не в дочерних.
  • Конфликт с пользовательскими скроллами: если вы используете библиотеки вроде ngx-scrollbar или кастомный скролл-контейнер, стандартный window.scrollTo может не работать. В таком случае нужно скроллить сам контейнер.

Пример для кастомного контейнера (если у вас overflow: auto на <div class="content">):


this.router.events.pipe(
  filter(event => event instanceof NavigationEnd)
).subscribe(() => {
  const content = document.querySelector('.content');
  if (content) {
    content.scrollTop = 0;
  }
});

Практический пример: полный код для реального проекта

Давайте соберём всё вместе. Допустим, у вас есть типичное приложение с боковым меню и контентом. Чтобы Angular 2 scroll to top on route change работал идеально, сделайте так:

Шаг 1. В app-routing.module.ts:


const routes: Routes = [
  { path: '', redirectTo: '/home', pathMatch: 'full' },
  { path: 'home', component: HomeComponent },
  { path: '                

Блоги

Рекомендаций по книгам