AngularInDepth уходит от Medium. Эта статья, ее обновления и более свежие статьи размещены на новой платформе inDepth.dev
Некоторые новые функции были добавлены в Angular Router с версией 7.1.0:
- Охрана маршрутизатора теперь может возвращать
UrlTree
. Это позволяет охраннику отменить текущую навигацию и перенаправить на URL-адрес, представленныйUrlTree
. - Теперь существует понятие «приоритета охраны», которое используется в качестве решающего фактора, когда несколько охранников возвращают
UrlTree
во время одной навигации. - Добавлен новый параметр конфигурации для
runGuardsAndResolvers
под названиемpathParamsChange
.
В этой статье мы узнаем, как начать использовать эти новые функции. Мы также поймем их мотивы и посмотрим, как они реализованы в исходных кодах Angular.
Джейсон Аден затронул многие из этих тем в своем прекрасном выступлении на AngularConnect 2018, так что обязательно ознакомьтесь с ним. Маршрутизаторская часть его выступления начинается здесь.
Выполните навигацию / перенаправления от охранников, вернув UrlTree
Мотивация
До этого изменения, когда во время навигации выполнялось несколько охранников, каждый из них мог запускать навигацию, вызывая navigateByUrl
. В таких сценариях было неясно, какая навигация охранника должна выиграть.
С этим изменением средство защиты с наивысшим приоритетом, которое возвращает UrlTree
, отменит текущую навигацию, и будет выполнено перенаправление на URL-адрес, представленный возвращенным UrlTree
.
Мы скоро увидим, что означает «высший приоритет».
Фон
Прежде чем углубляться в это изменение, стоит понять разницу между URL и UrlTree.
Внутри Angular Router строка URL-адреса представлена с использованием структуры, называемой UrlTree
. Строковый URL-адрес легко преобразовать в UrlTree с помощью parseUrl
метода службы Router
:
const url = 'target'; const tree: UrlTree = this.router.parseUrl(url);
Если вы хотите узнать больше о взаимосвязи между URL-адресами и UrlTrees в Angular, я подробно рассказал о них в этой статье.
Перемена
До этого изменения охрана маршрутизатора могла возвращать только boolean
значений. Возвращаемое значение true
означает, что навигация может продолжаться, а возвращаемое значение false
отменяет навигацию.
Теперь для CanActivate
, CanActivateChild
и CanDeactivate
есть третий вариант; эти охранники могут вернуть UrlTree
напрямую. В этих сценариях текущая навигация отменяется и создается новая навигация, которая направляется по пути, указанному возвращенным UrlTree
. Например, если пользователь не проходит проверку подлинности, вы можете перенаправить этого пользователя прямо на страницу входа.
Пример
https://stackblitz.com/edit/router-redirects-from-guards
В этом примере приложения есть два маршрута:
Мы сделаем так, чтобы /redir
всегда перенаправлял на /target
вместо отображения NeverGetHereComponent
. Вместо того, чтобы использовать redirectTo: 'target'
внутри определения маршрута для path: 'redir'
, мы позволим CanActivateRouteGuard
инициировать перенаправление.
Мы начнем с обычной сторожевой функции и изменим ее canActivate
метод, чтобы он возвращал UrlTree
вместо логического значения:
Как упоминалось ранее, parseUrl
- это функция службы маршрутизатора. Он принимает URL-адрес, закодированный в виде строки, и преобразует его в UrlTree
.
Наша охрана готова, поэтому мы прикрепим ее к { path: 'redir' ... }
маршруту.
{ path: 'redir', component: NeverGetHereComponent, canActivate:[CanActivateRouteGuard] }
Теперь, когда мы направляемся к /redir
, навигация будет продолжаться в обычном режиме, пока не будет проверена охрана. Когда наша функция защиты возвращает UrlTree
, указывающий на target
, переход к redir
будет отменен, и начнется новая навигация с таргетингом на target
. Мы можем подтвердить это, щелкнув ссылку перенаправления в Stackblitz:
а затем проверьте консоль браузера:
Это все, что нужно для настройки переадресации от маршрутных охранников!
Guard Priority
У нас часто есть несколько охранников, охраняющих маршрут. Вам может быть интересно, что происходит, когда несколько охранников пытаются выполнить перенаправление во время навигации. Что, если несколько из этих охранников вернут UrlTrees?
В Angular 7.1.0 есть понятие приоритета защиты. Приоритет защиты реализуется внутри с помощью специального оператора RxJS, называемого prioritizedGuardValue
. Мы не будем здесь вдаваться в подробности реализации, но этот оператор будет следить за тем, чтобы охранник с наивысшим приоритетом выигрывал всякий раз, когда несколько охранников возвращают UrlTrees.
Рассмотрим следующий пример:
Вот как рассчитывается приоритет охраны для нескольких canActivate
охранников:
canActivate
охранников текущего маршрута обрабатываются перед любымиcanActivate
охранниками его дочерних элементов.- Внутри массива
canActivate
защита с индексом 0 имеет наивысший приоритет, за ней следует защита с индексом 1 и так далее.
Другой способ мышления о canActivate
состоит в том, что защита, ближайшая к корню приложения, имеет наивысший приоритет. Итак, в приведенном выше фрагменте наивысший приоритет имеет CanActivateRouteGuard
, за ним следует CanActivateRouteGuard2
, а затем ChildCanActivateRouteGuard
.
Все средства защиты в заданном массиве canActivate
выполняются параллельно, но маршрутизатор будет ждать, пока все средства защиты с более высоким приоритетом закончатся, прежде чем двигаться дальше. Итак, в приведенном выше примере:
- Даже если
CanActivateRouteGuard2
немедленно возвращаетUrlTree
:
маршрутизатор все равно будет ждать разрешенияCanActivateRouteGuard
, прежде чем инициировать новую навигацию. - Если
CanActivateRouteGuard
вернетUrlTree
:
, это выиграет. - Если он возвращает
false
:
, вся навигация не выполняется (и перенаправления не происходит). - Если он просто возвращает
true
:
, тогда будет выполнено переход к UrlTree, возвращаемомуCanActivateRouteGuard2
.
Вы можете увидеть, как развиваются различные сценарии, посмотрев на тесты для оператора PrioritizedGuardValue.
Вы также можете поэкспериментировать с этим stackblitz. Я рекомендую перейти к трем охранникам и изменить их задержки и возвращаемые значения, а также их порядок в массиве canActivate
в app.module.ts
.
runGuardsAndResolvers имеет новую опцию: pathParamsChange
Официальная документация описывает параметр runGuardsAndResolvers
как:
определяет, когда будут запускаться охранники и резолверы. По умолчанию они запускаются только при изменении матричных параметров маршрута. Если установлено значение
paramsOrQueryParamsChange
, они также будут запускаться при изменении параметров запроса. И если установлено значениеalways
, они будут запускаться каждый раз.
С новой опцией pathParamsChange
функции защиты и преобразователя будут запускаться только при изменении пути или параметров пути. Изменения любых других типов параметров, таких как параметры матрицы или параметры запроса, не приведут к запуску средств защиты и преобразователей.
Мотивация
Как описано в Источниках:
`pathParamsChange` Запустить путь охранников и преобразователей или любое изменение параметров пути. Этот режим * полезен, если вы хотите игнорировать изменения всех необязательных параметров, таких как параметры запроса * и * матрицы *.
Пример использования
runGuardsAndResolvers
- это свойство Routes, поэтому оно используется в конфигурации маршрута:
{ path: '...', runGuardsAndResolvers: 'pathParamsChange'}
Резюме
С выпуском Angular 7.1.0 функции Route Guard теперь имеют возможность возвращать UrlTree
для отмены текущей навигации и перенаправления на маршрут.
Чтобы инициировать перенаправление из функции защиты, сделайте следующее:
- Создайте функцию защиты, которая использует
parseUrl
для возврата UrlTree. - Зарегистрируйте охранника с маршрутом, как обычно
Также есть новая опция для указания того, когда запускать резолверы и функции защиты, называемые pathParamsChange
, которая полезна, когда вы хотите запускать охранники и резолверы только для основных переходов и игнорировать любые дополнительные параметры, такие как матрица или параметры запроса.
Особая благодарность Джейсону Адену, Максу «Волшебнику» Корецкому и Тиму Дешрайверу за их помощь в написании этой статьи.