Маршрутизация позволяет сопоставлять запросы к приложению с определенными ресурсами внутри приложения.
Ключевым для работы маршрутизации является модуль RouterModule, который располагается в пакете @angular/router. Поэтому при работе с маршрутизацией этот пакет должен быть указан в списке зависимостей в файле package.json:
{ "name": "helloapp", "version": "1.0.0", "description": "First Angular 17 Project", "author": "Eugene Popov <metanit.com>", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build" }, "dependencies": { "@angular/router": "~17.0.0", // остальные пакеты }, "devDependencies": { // остальные пакеты } }
Для определения маршрутов возьмем базовую структуру приложения:
Для работы с маршрутизацией в первую очередь стоит определить базовый адрес приложения. Для этого возьмем веб-страницу index.html
и добавим в секцию <head>
элемент <base>
:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <base href="/" /> <title>Hello Angular 17</title> </head> <body> <my-app>Загрузка...</my-app> </body> </html>
В качестве базового адреса будет рассматриваться корень приложения.
Каждый маршрут сопоставляется с определенным компонентом. Поэтому добавим в проект ряд компонентов. Так, добавим в папку src/app новый файл home.component.ts:
import { Component} from "@angular/core"; @Component({ selector: "home-app", template: "<h2>Главная</h2>" }) export class HomeComponent { }
Этот простенький компонент выводит обычный заголовок.
Далее добавим в папку src/app новый файл about.component.ts:
import { Component} from "@angular/core"; @Component({ selector: "about-app", template: "<h2>О сайте</h2>" }) export class AboutComponent { }
И также добавим еще один файл not-found.component.ts:
import { Component} from "@angular/core"; @Component({ selector: "not-found-app", template: "<h2>Страница не найдена</h2>" }) export class NotFoundComponent { }
Итак, кроме главного компонента AppComponent в проекте определено еще три компонента, каждый из которых просто выводит некоторый заголовок. Для каждого из этих компонентов мы можем определить свой маршрут. Для этого добавим в папке src/app новый файл app.config.ts со следующим содержимым:
import { provideRouter, Routes } from "@angular/router"; import { ApplicationConfig } from "@angular/core"; // компоненты, которые сопоставляются с маршрутами import {HomeComponent} from "./home.component"; import {AboutComponent} from "./about.component"; import {NotFoundComponent} from "./not-found.component"; // определение маршрутов const appRoutes: Routes =[ { path: "", component: HomeComponent}, { path: "about", component: AboutComponent}, { path: "**", component: NotFoundComponent } ]; export const appConfig: ApplicationConfig = { providers: [provideRouter(appRoutes)] };
Во-первых, здесь импортируются функция providerRouter
(для установки маршрутов) и класс Routes
, который представляет коллекцию маршрутов:
import { provideRouter, Routes } from "@angular/router";
Для приложения маршруты устанавливаются как часть конфигурации приложения, которая представляет класс ApplicationConfig. Соответственно также импортируем данный класс:
import { ApplicationConfig } from "@angular/core";
Далее определяется сам набор маршрутов:
import {HomeComponent} from "./home.component"; import {AboutComponent} from "./about.component"; import {NotFoundComponent} from "./not-found.component"; // определение маршрутов const appRoutes: Routes =[ { path: "", component: HomeComponent}, { path: "about", component: AboutComponent}, { path: "**", component: NotFoundComponent } ];
Здесь определено три маршрута, каждый из которых будет обрабатываться отдельным компонентом. Для указания маршрута применяется параметр path
.
Например, путь "about" будет представлять запрос типа "http://localhost:3000/about" и будет обрабатываться классом AboutComponent.
Если запрос не содержит никаких сегментов, например, просто имя домена "http://localhost:3000/", то такой запрос будет сопоставляться с путем "" (пустая строка) и будет обрабатываться компонентом HomeComponent.
Если приложение получит запрос, который не подходит ни под один из выше определенных маршрутов, то он будет сопоставляться с шаблоном "**", где две звездочки представляют любой путь.
Чтобы применить маршруты, создаем объект ApplicationConfig и устанавливаем его свойство providers
:
export const appConfig: ApplicationConfig = { providers: [provideRouter(appRoutes)] };
Здесь в коллекцию providers
передается результат функции provideRouter()
. Эта функция принимает коллекцию маршрутов Routes и использует их
для настройки сервиса Router. Когда приложение загружается, Router выполняет начальную навигацию по текущему URL, который стоит в адресной строке браузера.
Однако мы только определили конфигурацию приложения в виде объекта appConfig. Теперь его надо применить к приложению. Для этого перейдем к файлу main.ts и изменим его следующим образом:
import { bootstrapApplication } from "@angular/platform-browser"; import { AppComponent } from "./app/app.component"; import {appConfig} from "./app/app.config"; bootstrapApplication(AppComponent, appConfig);
Вторым, необязательным параметров функции bootstrapApplication()
передается конфигурация приложения ApplicationConfig. И в данном случае передаем наш объект appConfig,
который будет настраивать систему маршрутизации.
Мы определили три разных компонента для разных маршрутов, однако в качестве главного компонента выступает AppComponent. Этот компонент выступает в качестве контейнера для остальных компонентов, которые будут обслуживать запросы к приложению.
Но чтобы можно было внедрить в AppComponent тот компонент, который обрабатывает запрос, необходимо использовать элемент RouterOutlet. Для этого изменим код AppComponent:
import { Component} from "@angular/core"; import { RouterOutlet} from "@angular/router"; @Component({ selector: "my-app", standalone: true, imports: [RouterOutlet], template: `<div> <h1>Приложение Angular</h1> <router-outlet></router-outlet> </div>`, }) export class AppComponent {}
На место элемента <router-outlet>
будет рендериться компонент, выбранный для обработки запроса.
В итоге проект будет выглядеть следующим образом:
Запустим приложение. По умолчанию приложение запускается без сегментов, поэтому запрос обрабатывает HomeComponent:
Перейдем по пути "localhost:xxxx/about":
При переходе к любому другому адресу сработает компонент NotFoundComponent:
Когда будет выполняться переход по определенному пути, например, "/about", система маршрутизации сопоставляет последовательно URL запроса с
параметрами path у каждого маршрута. Данный процесс называется url matching. В частности, система маршрутизации сопоставит url "/about" с маршрутом { path: "about", component: AboutComponent}
.
И компонент AboutComponent будет выбран для обработки запроса по пути /about
.
Но при определении маршрутов следует учитывать их порядок. Вполне возможно, что под определенный запрос будет соответствовать сразу несколько маршрутов. В этом случае запрос будет обрабатываться первым из них. Другие же маршруты не будут учитываться. Например, если мы изменим порядок маршрутов:
const appRoutes: Routes =[ { path: "**", component: NotFoundComponent }, { path: "", component: HomeComponent}, { path: "about", component: AboutComponent} ];
То в этом случае запрос /about
будет обрабатываться первым маршрутом, поскольку он соответствует запросу /about
(путь "**" соответствует любому набору символов). Поэтому маршрут
{ path: "**", component: NotFoundComponent }
лучше определить последним - для всех тех запросов, которые не будут соответствовать ни одному из выше определенных маршрутов.
Вполне возможно, что по какому-то маршруту мы захотим сделать переадресацию по другому пути. Например, в случае, если нужного маршрута для запроса не найдено, мы можем переадресовать на главную страницу:
const appRoutes: Routes =[ { path: "", component: HomeComponent}, { path: "about", component: AboutComponent}, { path: "**", redirectTo: "/"} ];
Для переадресации указываем параметр redirectTo. Его значение представляет путь переадресации. В данном случае слеш указывает на первый маршрут или на главную страницу.
Также мы можем задать критерий соответствия строки запроса маршруту с помощью параметра pathMatch:
const appRoutes: Routes =[ { path: "", component: HomeComponent}, { path: "about", component: AboutComponent}, { path: "contact", redirectTo: "/about", pathMatch:"full"}, { path: "**", redirectTo: "/"} ];
Значение pathMatch:"full"
указывает, что запрошенный адрес должен полностью соответствовать маршруту, то есть должно быть полное соответствие.
Например, запрос /contact полностью соотвествует маршруту { path: "contact", redirectTo: "/about", pathMatch:"full"}
,
поэтому будет выполняться переадресация на адрес /about.
А запрос /contact/5 не будет соответствовать этому маршруту, так как после "contact" идут другие сегменты.