Добавьте навигацию с маршрутизацией¶
28.02.2022
Приложение Tour of Heroes имеет новые требования:
- Добавить представление Приборная доска.
- Добавить возможность навигации между представлениями Герои и Панель.
- Когда пользователи нажимают на имя героя в любом из представлений, переходят к детальному представлению выбранного героя.
- Когда пользователи нажимают на глубокую ссылку в электронном письме, открывается детальное представление для конкретного героя.
Пример приложения, которое описывается на этой странице, см.:
Когда вы закончите, пользователи смогут перемещаться по приложению следующим образом:
Добавьте модуль AppRoutingModule
¶
В Angular лучшей практикой является загрузка и настройка маршрутизатора в отдельном модуле верхнего уровня. Маршрутизатор предназначен для маршрутизации и импортируется корневым AppModule
.
По соглашению, имя класса модуля — AppRoutingModule
, и он находится в app-routing.module.ts
в директории src/app
.
Запустите ng generate
для создания модуля маршрутизации приложения.
1 |
|
Параметр | Детали |
---|---|
--flat | Помещает файл в src/app вместо его собственного каталога. |
--module=app | Приказывает ng generate зарегистрировать его в массиве imports модуля AppModule . |
Файл, который создает ng generate
, выглядит следующим образом:
1 2 3 4 5 6 7 8 |
|
Замените его на следующий:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Во-первых, файл app-routing.module.ts
импортирует RouterModule
и Routes
, чтобы приложение могло иметь возможность маршрутизации. Следующий импорт, HeroesComponent
, дает маршрутизатору место, куда он может перейти после настройки маршрутов.
Обратите внимание, что ссылки на CommonModule
и массив declarations
не нужны, поэтому они больше не являются частью AppRoutingModule
. Следующие разделы объясняют остальную часть AppRoutingModule
более подробно.
Маршруты¶
В следующей части файла вы настраиваете маршруты. Маршруты указывают маршрутизатору, какой вид отображать, когда пользователь нажимает на ссылку или вставляет URL в адресную строку браузера.
Поскольку app-routing.module.ts
уже импортирует HeroesComponent
, вы можете использовать его в массиве routes
:
1 2 3 |
|
Типичный Angular Route
имеет два свойства:
Свойства | Подробнее |
---|---|
path | Строка, которая соответствует URL в адресной строке браузера. |
component | Компонент, который маршрутизатор должен создать при переходе к этому маршруту. |
Это указывает маршрутизатору сопоставить URL с path: 'heroes'
и отобразить HeroesComponent
, когда URL будет таким, как localhost:4200/heroes
.
RouterModule.forRoot()
¶
Метаданные @NgModule
инициализируют маршрутизатор и запускают его прослушивание изменений местоположения браузера.
Следующая строка добавляет RouterModule
в массив imports
модуля AppRoutingModule
и конфигурирует его с routes
за один шаг, вызывая RouterModule.forRoot()
:
1 |
|
Метод называется forRoot()
, потому что вы настраиваете маршрутизатор на корневом уровне приложения. Метод forRoot()
предоставляет поставщиков услуг и директивы, необходимые для маршрутизации, и выполняет начальную навигацию на основе текущего URL браузера.
Далее, AppRoutingModule
экспортирует RouterModule
, чтобы он был доступен во всем приложении.
1 |
|
Добавьте RouterOutlet
¶
Откройте шаблон AppComponent
и замените элемент <app-heroes>
на элемент <router-outlet>
.
1 2 3 |
|
Шаблон AppComponent
больше не нуждается в <app-heroes>
, потому что приложение отображает HeroesComponent
только тогда, когда пользователь переходит к нему.
Шаблон <router-outlet>
указывает маршрутизатору, где отображать маршрутизируемые представления.
RouterOutlet
— это одна из директив маршрутизации, которая стала доступна для AppComponent
, потому что AppModule
импортирует AppRoutingModule
, который экспортировал RouterModule
. Команда ng generate
, которую вы выполнили в начале этого руководства, добавила этот импорт из-за флага --module=app
. Если вы не использовали команду ng generate
для создания app-routing.module.ts
, импортируйте AppRoutingModule
в app.module.ts
и добавьте его в массив imports
NgModule
.
Попробуйте¶
Если вы еще не обслуживаете свое приложение, запустите ng serve
, чтобы увидеть свое приложение в браузере.
Браузер должен обновиться и отобразить заголовок приложения, но не список героев.
Посмотрите на адресную строку браузера. URL заканчивается на /
.
Маршрутный путь к HeroesComponent
— /heroes
.
Добавьте /heroes
к URL в адресной строке браузера. Вы должны увидеть знакомое представление обзора/детализации героев.
Удалите /heroes
из URL в адресной строке браузера. Браузер должен обновиться и отобразить заголовок приложения, но не список героев.
Добавление навигационной ссылки с помощью routerLink
¶
В идеале пользователи должны иметь возможность нажать на ссылку для навигации, а не вставлять URL маршрута в адресную строку.
Добавьте элемент <nav>
и внутри него элемент якоря, который при нажатии вызывает навигацию к HeroesComponent
. Измененный шаблон AppComponent
выглядит следующим образом:
1 2 3 4 5 6 |
|
Атрибут routerLink
установлен в "/heroes"
, строку, которую маршрутизатор сопоставляет с маршрутом к HeroesComponent
. Атрибут routerLink
является селектором для директивы RouterLink
, которая превращает клики пользователя в навигацию по маршрутизатору.
Это еще одна из публичных директив в RouterModule
.
Браузер обновляется и отображает заголовок приложения и ссылку на героев, но не список героев.
Щелкните по ссылке. Адресная строка обновляется до /heroes
, и появляется список героев.
Чтобы эта и будущие навигационные ссылки выглядели лучше, добавьте частные CSS стили в app.component.css
, как указано в финальном обзоре кода ниже.
Добавьте представление приборной панели¶
Маршрутизация имеет больше смысла, когда ваше приложение имеет более одного представления, однако приложение Тур героев имеет только представление героев.
Чтобы добавить DashboardComponent
, запустите ng generate
, как показано здесь:
1 |
|
ng generate
создает файлы для DashboardComponent
и объявляет его в AppModule
.
Замените содержимое по умолчанию в этих файлах, как показано здесь:
1 2 3 4 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
|
Шаблон template представляет сетку ссылок на имена героев.
- Повторитель
*ngFor
создает столько ссылок, сколько находится в массивеheroes
компонента. - Ссылки оформляются как цветные блоки в
dashboard.component.css
. - Ссылки пока никуда не ведут.
Класс class похож на класс HeroesComponent
.
- Он определяет свойство массива
heroes
. - Конструктор ожидает, что Angular внедрит
HeroService
в приватное свойствоheroService
. - Хук жизненного цикла
ngOnInit()
вызываетgetHeroes()
.
Эта getHeroes()
возвращает нарезанный список героев на позициях 1 и 5, возвращая только героев два, три, четыре и пять.
1 2 3 4 |
|
Добавьте маршрут к приборной панели¶
Чтобы перейти к приборной панели, маршрутизатору нужен соответствующий маршрут.
Импортируйте DashboardComponent
в файл app-routing.module.ts
.
1 |
|
Добавьте маршрут в массив routes
, который соответствует пути к DashboardComponent
.
1 |
|
Добавьте маршрут по умолчанию¶
Когда приложение запускается, адресная строка браузера указывает на корень сайта. Это не совпадает ни с одним существующим маршрутом, поэтому маршрутизатор никуда не переходит.
Пространство под <router-outlet>
пустует.
Чтобы приложение автоматически переходило на приборную панель, добавьте следующий маршрут в массив routes
.
1 |
|
Этот маршрут перенаправляет URL, полностью соответствующий пустому пути, на маршрут, путь которого '/dashboard'
.
После обновления браузера маршрутизатор загружает DashboardComponent
и в адресной строке браузера отображается URL /dashboard
.
Добавление ссылки на приборную панель в оболочку¶
Пользователь должен иметь возможность перемещаться между DashboardComponent
и HeroesComponent
, нажимая на ссылки в области навигации в верхней части страницы.
Добавьте навигационную ссылку на приборную панель в шаблон оболочки AppComponent
, чуть выше ссылки Heroes.
1 2 3 4 5 6 7 |
|
После обновления браузера вы можете свободно перемещаться между двумя представлениями, щелкая по ссылкам.
Переход к деталям героя¶
Компонент HeroDetailComponent
отображает подробную информацию о выбранном герое. В настоящее время компонент HeroDetailComponent
виден только в нижней части компонента HeroesComponent
.
Пользователь должен иметь возможность получить доступ к этим деталям тремя способами.
- Нажав на героя в приборной панели.
- Щелкнув героя в списке героев.
- Вставляя URL "глубокой ссылки" в адресную строку браузера, который идентифицирует героя для отображения.
Этот раздел позволяет перейти к компоненту HeroDetailComponent
и освободить его от компонента HeroesComponent
.
Удалить детали героя из HeroesComponent
¶
Когда пользователь нажимает на героя в HeroesComponent
, приложение должно перейти к HeroDetailComponent
, заменив представление списка героев на представление подробностей о герое. Представление списка героев больше не должно показывать детали героя, как это происходит сейчас.
Откройте файл heroes/heroes.component.html
и удалите элемент <app-hero-detail>
снизу.
Щелчок по элементу героя теперь ничего не делает. Вы можете исправить это после того, как включите маршрутизацию к HeroDetailComponent
.
Добавьте маршрут геройской детализации¶
URL типа ~/detail/11
будет хорошим URL для перехода к представлению Hero Detail героя, чей id
равен 11
.
Откройте app-routing.module.ts
и импортируйте HeroDetailComponent
.
1 |
|
Затем добавьте параметризованный маршрут в массив routes
, который соответствует шаблону пути к представлению геройская деталь.
1 |
|
Символ двоеточия :
в пути
указывает на то, что :id
является заполнителем для конкретного героя id
.
На данном этапе все маршруты приложения уже созданы.
1 2 3 4 5 6 7 8 9 10 |
|
DashboardComponent
ссылки на героев¶
Ссылки героев DashboardComponent
на данный момент ничего не делают.
Теперь, когда маршрутизатор имеет маршрут к HeroDetailComponent
, исправьте ссылки героев приборной панели для навигации с помощью параметризированного маршрута приборной панели.
1 2 3 4 5 6 |
|
Вы используете Angular interpolation binding внутри повторителя *ngFor
для вставки hero.id
текущей итерации в каждый routerLink
.
HeroesComponent
ссылки на героев¶
Элементы-герои в HeroesComponent
представляют собой <li>
элементы, события нажатия на которые привязаны к методу onSelect()
компонента.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Удалите внутренний HTML из <li>
. Оберните значок и имя в якорный элемент <a>
.
Добавьте к якорю атрибут routerLink
, такой же, как в шаблоне приборной панели.
1 2 3 4 5 6 7 8 |
|
Обязательно исправьте частную таблицу стилей в heroes.component.css
, чтобы список выглядел как раньше. Исправленные стили находятся в финальном обзоре кода внизу этого руководства.
Удаление мертвого кода — необязательно¶
Хотя класс HeroesComponent
все еще работает, метод onSelect()
и свойство selectedHero
больше не используются.
Неплохо привести все в порядок для вашего будущего. Вот класс после обрезки мертвого кода.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Маршрутизируемый HeroDetailComponent
¶
Родительский HeroesComponent
использовался для установки свойства HeroDetailComponent.hero
и HeroDetailComponent
отображал героя.
Теперь HeroesComponent
этого не делает. Теперь маршрутизатор создает HeroDetailComponent
в ответ на URL, такой как ~/detail/12
.
Компоненту HeroDetailComponent
нужен новый способ заставить героя отображаться. В этом разделе объясняется следующее:
- Получить маршрут, который его создал
- Извлечь
id
из маршрута - Получите героя с этим
id
с сервера, используяHeroService
.
Добавьте следующие импорты:
1 2 3 4 |
|
Вставьте в конструктор сервисы ActivatedRoute
, HeroService
и Location
, сохранив их значения в приватных полях:
1 2 3 4 5 |
|
В ActivatedRoute
хранится информация о маршруте к данному экземпляру HeroDetailComponent
. Этот компонент интересуют параметры маршрута, извлеченные из URL.
Параметр "id" — это id
героя для отображения.
Сервис HeroService
получает данные о героях с удаленного сервера, и этот компонент использует их для получения героя для отображения.
location
— это сервис Angular для взаимодействия с браузером. Этот сервис позволяет вам вернуться к предыдущему представлению.
Извлечение параметра маршрута id
¶
В ngOnInit()
lifecycle hook вызовите getHero()
и определите его следующим образом.
1 2 3 4 5 6 7 8 9 |
|
Снимок route.snapshot
— это статическое изображение информации о маршруте сразу после создания компонента.
paramMap
— это словарь значений параметров маршрута, извлеченных из URL. Ключ "id"
возвращает id
героя для выборки.
Параметры маршрута всегда являются строками. Функция JavaScript Number
преобразует строку в число, которым и должен быть id
героя.
Браузер обновляется, и приложение падает с ошибкой компилятора. У HeroService
нет метода getHero()
.
Добавьте его сейчас.
Добавьте HeroService.getHero()
¶
Откройте HeroService
и добавьте следующий метод getHero()
с id
после метода getHeroes()
:
1 2 3 4 5 6 7 |
|
Символы backtick ( `
) определяют JavaScript template literal для встраивания id
.
Как и getHeroes()
, getHero()
имеет асинхронную сигнатуру. Она возвращает макет героя как Observable
, используя функцию RxJS of()
.
Вы можете переписать getHero()
как настоящий Http
запрос без необходимости изменять HeroDetailComponent
, который его вызывает.
Попробуйте¶
Браузер обновляется, и приложение снова работает. Вы можете щелкнуть героя на приборной панели или в списке героев и перейти к детальному представлению этого героя.
Если вы введете localhost:4200/detail/12
в адресную строку браузера, маршрутизатор перейдет к детальному представлению для героя с id: 12
, Dr Nice.
Найти дорогу назад¶
Нажав кнопку "Назад" в браузере, вы можете вернуться на предыдущую страницу. Это может быть список героев или представление приборной панели, в зависимости от того, что отправило вас к детальному представлению.
Было бы неплохо иметь кнопку на представлении HeroDetail
, которая могла бы это сделать.
Добавьте кнопку go back в нижнюю часть шаблона компонента и привяжите ее к методу компонента goBack()
.
1 |
|
Добавьте метод goBack()
в класс компонента, который перемещается на один шаг назад в стеке истории браузера, используя службу Location
, которую вы использовали для инъекции.
1 2 3 |
|
Обновите браузер и начните кликать. Теперь пользователи могут перемещаться по приложению с помощью новых кнопок.
Детали выглядят лучше, если добавить частные CSS стили в hero-detail.component.css
, как указано в одной из вкладок "final code review" ниже.
Окончательный обзор кода¶
Здесь представлены файлы кода, обсуждаемые на этой странице.
AppRoutingModule
, AppModule
и HeroService
¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
AppComponent
¶
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
DashboardComponent
¶
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
|
HeroesComponent
¶
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
|
HeroDetailComponent
¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Резюме¶
- Вы добавили маршрутизатор Angular для навигации между различными компонентами
- Вы превратили
AppComponent
в навигационную оболочку со ссылками<a>
и<router-outlet>
. - Вы сконфигурировали маршрутизатор в модуле
AppRoutingModule
. - Определены маршруты, маршрут перенаправления и параметризованный маршрут
- использована директива
routerLink
в элементах якоря - Рефакторинг тесно связанного представления main/detail в маршрутизируемое представление detail
- использование параметров ссылки маршрутизатора для перехода к детальному представлению выбранного пользователем героя
- Вы разделили
HeroService
с другими компонентами