Добавьте навигацию с маршрутизацией¶
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с другими компонентами
