Маршрутизация в одностраничных приложениях

Маршрутизация в Angular — это процесс управления переходами между различными представлениями или компонентами в приложении. В контексте одностраничных приложений (SPA) маршрутизация позволяет изменять содержимое страницы без необходимости перезагрузки всего документа, предоставляя пользователю более быстрые и плавные взаимодействия с интерфейсом.

Маршрутизация в Angular осуществляется через модуль @angular/router. Он предоставляет все необходимые инструменты для создания маршрутов, управления навигацией и обработки параметров маршрутов. Важнейшим компонентом является RouterModule, который необходимо импортировать в основной модуль приложения.

Для начала маршрутизации нужно создать массив маршрутов, который будет ассоциировать URL-пути с компонентами. Вот пример базовой конфигурации маршрутов:

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

В этом примере:

  • Путь /home отображает компонент HomeComponent.
  • Путь /about отображает компонент AboutComponent.
  • Пустой путь '' перенаправляет пользователя на маршрут /home.

После того как маршруты настроены, их нужно подключить в главном модуле с помощью RouterModule.forRoot().

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppModule { }

Навигация между маршрутами

Для навигации между маршруты используются директивы routerLink и методы Router.

Директива routerLink привязывает URL-путь к элементу, обычно используемому в ссылках или кнопках. Она автоматически управляет навигацией при клике.

Пример использования в шаблоне компонента:

<a routerLink="/home">Главная</a>
<a routerLink="/about">О нас</a>

Директива автоматически отслеживает изменения URL и подставляет нужный компонент.

Метод navigate()

Для программной навигации используется метод navigate() объекта Router. Это может быть полезно, например, при обработке событий или после выполнения определённой логики.

Пример использования:

import { Router } from '@angular/router';

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

  navigateToAbout() {
    this.router.navigate(['/about']);
  }
}

Параметры маршрутов

Маршруты в Angular могут содержать параметры, которые передаются при навигации. Для указания параметров в маршруте используется синтаксис :param.

Пример:

const routes: Routes = [
  { path: 'user/:id', component: UserComponent }
];

Здесь параметр id будет доступен в компоненте через ActivatedRoute:

import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
  userId: string;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.userId = this.route.snapshot.paramMap.get('id');
  }
}

Кроме того, для получения параметров можно использовать наблюдаемые значения, что позволяет реагировать на изменения параметров без перезагрузки компонента:

this.route.paramMap.subscribe(params => {
  this.userId = params.get('id');
});

Защита маршрутов

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

Guard может быть реализован как сервис, который проверяет, разрешено ли пользователю перейти на данный маршрут. Пример создания и использования Guard:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  constructor(private router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
    if (/* условие авторизации */) {
      return true;
    } else {
      this.router.navigate(['/login']);
      return false;
    }
  }
}

Чтобы применить этот Guard к маршруту, достаточно добавить его в свойство canActivate:

const routes: Routes = [
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }
];

Режимы маршрутизации

В Angular доступны два режима маршрутизации: HashLocationStrategy и PathLocationStrategy.

  • HashLocationStrategy: Используется, когда маршруты управляются через хэш в URL (например, www.example.com/#/home). Этот режим работает в старых браузерах и не требует настроек на сервере.
  • PathLocationStrategy: Этот режим использует чистые пути (например, www.example.com/home) и требует, чтобы сервер правильно обрабатывал запросы, возвращая правильный ресурс при перезагрузке страницы.

По умолчанию используется PathLocationStrategy. Для использования HashLocationStrategy нужно указать это в конфигурации маршрутизатора:

import { LocationStrategy, HashLocationStrategy } from '@angular/common';

@NgModule({
  providers: [{ provide: LocationStrategy, useClass: HashLocationStrategy }]
})
export class AppModule {}

Ленивая загрузка

Ленивая загрузка (Lazy Loading) позволяет загружать модули только тогда, когда они реально нужны, что улучшает производительность приложения. В Angular ленивая загрузка реализуется через маршруты.

Для реализации ленивая загрузка нужно настроить маршруты таким образом, чтобы модули загружались только по мере необходимости. Это делается с использованием loadChildren.

Пример конфигурации маршрутов с ленивой загрузкой:

const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
  }
];

При этом сам модуль AdminModule будет загружен только при переходе на путь /admin.

Режимы навигации

Angular поддерживает несколько режимов навигации, которые управляют поведением при изменении маршрута. К таким режимам относится onSameUrlNavigation.

По умолчанию Angular не будет повторно активировать компонент, если маршрут не изменился. Однако можно изменить это поведение, установив параметр onSameUrlNavigation в reload.

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })
  ]
})
export class AppModule { }

Использование маршрутов внутри компонентов

В Angular компонентам можно назначать маршруты с помощью директивы router-outlet. Это место, куда будет загружаться компонент, соответствующий текущему маршруту.

Пример:

<router-outlet></router-outlet>

Заключение

Маршрутизация в Angular — это мощный инструмент, который позволяет организовать переходы между компонентами и управлять представлением в одностраничных приложениях. Использование маршрутов, параметров, защиты маршрутов, ленивой загрузки и разных стратегий маршрутизации делает Angular гибким и эффективным инструментом для разработки масштабируемых приложений.