Хотя технически правильно, другие ответы выиграют от объяснения соответствия URL-адреса Angular и маршрута. Я не думаю, что вы можете полностью (простите за каламбур) понять, что pathMatch: fullделает, если вы вообще не знаете, как работает маршрутизатор.
Давайте сначала определим несколько основных вещей. Мы будем использовать этот адрес в качестве примера: /users/james/articles?from=134#section.
Это может быть очевидно, но сначала отметим, что параметры запроса ( ?from=134) и фрагменты ( #section) не играют никакой роли в сопоставлении путей . Имеет значение только базовый url ( /users/james/articles).
Angular разбивает URL-адреса на сегменты . Сегменты - /users/james/articlesэто, конечно users, jamesи articles.
Конфигурация маршрутизатора представляет собой древовидную структуру с одним корневым узлом. Каждый Routeобъект представляет собой узел, который может иметь childrenузлы, которые, в свою очередь, могут иметь другие childrenили быть листовыми узлами.
Цель маршрутизатора - найти ветвь конфигурации маршрутизатора , начинающуюся с корневого узла, которая соответствовала бы точно всем (!!!) сегментам URL. Это очень важно! Если Angular не находит ветку конфигурации маршрута, которая могла бы соответствовать всему URL-адресу - ни больше ни меньше - он ничего не отобразит .
Например, если ваш целевой URL-адрес, /a/b/cно маршрутизатор может сопоставить только либо /a/bили /a/b/c/d, то совпадения нет, и приложение ничего не отобразит.
Наконец, маршруты с redirectToведут себя немного иначе, чем обычные маршруты, и мне кажется, что они будут единственным местом, где кто-то действительно когда-либо захочет воспользоваться pathMatch: full. Но мы вернемся к этому позже.
Соответствие prefixпути по умолчанию ( )
Причина названия prefixзаключается в том, что такая конфигурация маршрута будет проверять, является ли сконфигурированный pathпрефиксом оставшихся сегментов URL. Однако маршрутизатор может сопоставлять только полные сегменты , что немного сбивает с толку это наименование.
В любом случае, допустим, это наша конфигурация маршрутизатора корневого уровня:
const routes: Routes = [
{
path: 'products',
children: [
{
path: ':productID',
component: ProductComponent,
},
],
},
{
path: ':other',
children: [
{
path: 'tricks',
component: TricksComponent,
},
],
},
{
path: 'user',
component: UsersonComponent,
},
{
path: 'users',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
},
];
Обратите внимание, что каждый отдельный Routeобъект здесь использует стратегию сопоставления по умолчанию, то есть prefix. Эта стратегия означает, что маршрутизатор выполняет итерацию по всему дереву конфигурации и пытается сопоставить его с целевым URL-адресом сегмент за сегментом, пока URL-адрес не будет полностью сопоставлен . Вот как это будет сделано для этого примера:
- Обходите корневой массив в поисках точного совпадения для первого сегмента URL -
users.
'products' !== 'users', так что пропустите эту ветку. Обратите внимание, что мы используем проверку на равенство, а не .startsWith()или .includes()- учитываются только совпадения полного сегмента!
:otherсоответствует любому значению, так что это совпадение. Однако целевой URL еще не полностью сопоставлен (нам все еще нужно сопоставить jamesи articles), поэтому маршрутизатор ищет дочерние элементы.
- Единственный ребенок
:otherIS tricks, который !== 'james', следовательно , не совпадают.
- Затем Angular возвращается к корневому массиву и продолжает оттуда.
'user' !== 'users, пропустить ветку.
'users' === 'users- сегмент совпадает. Однако это еще не полное совпадение, поэтому нам нужно искать детей (как в шаге 3).
'permissions' !== 'james', пропустить это.
:userIDсоответствует чему угодно, таким образом, мы имеем совпадение для jamesсегмента. Однако это еще не полное совпадение, поэтому нам нужно искать дочерний элемент, который бы совпадал articles.
- Мы видим, что у
:userIDнего есть дочерний маршрут articles, который дает нам полное совпадение! Таким образом приложение выполняет рендеринг UserArticlesComponent.
Соответствие полного URL ( full)
Пример 1
Теперь представьте, что usersобъект конфигурации маршрута выглядел так:
{
path: 'users',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
Обратите внимание на использование pathMatch: full. Если бы это было так, шаги 1-5 были бы такими же, но шаг 6 был бы другим:
'users' !== 'users/james/articles- сегмент не совпадает, потому что конфигурация пути usersс pathMatch: fullне соответствует полному URL-адресу, а именно users/james/articles.
- Так как совпадений нет, мы пропускаем эту ветку.
- На этом этапе мы достигли конца настройки маршрутизатора, не найдя совпадения. Приложение ничего не отображает .
Пример 2
Что, если бы у нас было это:
{
path: 'users/:userID',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
}
users/:userIDpathMatch: fullтолько с совпадениями, users/jamesпоэтому снова нет совпадений, и приложение ничего не отображает.
Пример 3
Давайте рассмотрим это:
{
path: 'users',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
В этом случае:
'users' === 'users- сегмент совпадает, но по- james/articlesпрежнему не совпадает . Поищем детей.
'permissions' !== 'james' - пропускать.
:userID'может соответствовать только одному сегменту, который был бы james. Однако это pathMatch: fullмаршрут, и он должен совпадать james/articles(весь оставшийся URL). Он не может этого сделать, и поэтому это не совпадение (поэтому мы пропускаем эту ветку)!
- Опять же, нам не удалось найти совпадения для URL-адреса, и приложение ничего не отображает .
Как вы могли заметить, pathMatch: fullконфигурация в основном говорит следующее:
Не обращай внимания на моих детей и сравнивайся только со мной. Если я не могу самостоятельно сопоставить все оставшиеся сегменты URL, продолжайте.
Перенаправления
Любой Routeобъект, для которого задан a, redirectToбудет сопоставлен с целевым URL-адресом в соответствии с теми же принципами. Единственная разница в том, что перенаправление применяется, как только сегмент совпадает . Это означает, что если маршрут перенаправления использует prefixстратегию по умолчанию , частичного совпадения достаточно, чтобы вызвать перенаправление . Вот хороший пример:
const routes: Routes = [
{
path: 'not-found',
component: NotFoundComponent,
},
{
path: 'users',
redirectTo: 'not-found',
},
{
path: 'users/:userID',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
];
Для нашего исходного URL ( /users/james/articles) вот что произойдет:
'not-found' !== 'users' - пропустить это.
'users' === 'users' - у нас есть матч.
- У этого совпадения есть
redirectTo: 'not-found', который применяется немедленно .
- Целевой URL изменится на
not-found.
- Маршрутизатор снова начинает сопоставление и сразу находит совпадение
not-found. Приложение отображает NotFoundComponent.
Теперь подумайте, что бы произошло, если бы в usersмаршруте также были pathMatch: full:
const routes: Routes = [
{
path: 'not-found',
component: NotFoundComponent,
},
{
path: 'users',
pathMatch: 'full',
redirectTo: 'not-found',
},
{
path: 'users/:userID',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
];
'not-found' !== 'users' - пропустить это.
usersбудет соответствовать первому сегменту URL-адреса, но конфигурация маршрута требует fullсовпадения, поэтому пропустите его.
'users/:userID'совпадения users/james. articlesвсе еще не найден, но у этого маршрута есть дочерние элементы.
- Мы находим совпадение
articlesв детях. Теперь соответствует весь URL-адрес, и приложение выполняет рендеринг UserArticlesComponent.
Пустой путь ( path: '')
Пустой путь - это особый случай, потому что он может соответствовать любому сегменту, не «потребляя» его (так что дочерним элементам придется снова сопоставить этот сегмент). Рассмотрим этот пример:
const routes: Routes = [
{
path: '',
children: [
{
path: 'users',
component: BadUsersComponent,
}
]
},
{
path: 'users',
component: GoodUsersComponent,
},
];
Допустим, мы пытаемся получить доступ /users:
path: ''всегда будет совпадать, следовательно, маршрут совпадает. Однако весь URL-адрес не был сопоставлен - нам все еще нужно сопоставить users!
- Мы видим, что есть дочерний элемент
users, который соответствует оставшемуся (и единственному!) Сегменту, и у нас есть полное совпадение. Приложение отображает BadUsersComponent.
Теперь вернемся к исходному вопросу
OP использовал эту конфигурацию маршрутизатора:
const routes: Routes = [
{
path: 'welcome',
component: WelcomeComponent,
},
{
path: '',
redirectTo: 'welcome',
pathMatch: 'full',
},
{
path: '**',
redirectTo: 'welcome',
pathMatch: 'full',
},
];
Если мы переходим к корневому URL ( /), вот как маршрутизатор решит это:
welcome не соответствует пустому сегменту, поэтому пропустите его.
path: ''соответствует пустому сегменту. У него есть pathMatch: 'full', что также удовлетворяет, поскольку мы сопоставили весь URL (у него был единственный пустой сегмент).
welcomeПроисходит перенаправление на , и приложение выполняет рендеринг WelcomeComponent.
Что, если не было pathMatch: 'full'?
Собственно, можно было бы ожидать, что все будет вести себя точно так же. Однако Angular явно запрещает такую конфигурацию ( { path: '', redirectTo: 'welcome' }), потому что, если вы поместите это Routeвыше welcome, теоретически это создаст бесконечный цикл перенаправлений. Итак, Angular просто выдает ошибку , поэтому приложение вообще не работает! ( https://angular.io/api/router/Route#pathMatch )
На самом деле, для меня это не имеет особого смысла, потому что Angular также реализовал защиту от таких бесконечных перенаправлений - он выполняет только одно перенаправление для каждого уровня маршрутизации! Это остановит все дальнейшие перенаправления (как вы увидите в примере ниже).
О чем path: '**'?
path: '**'будет соответствовать абсолютно чему угодно ( af/frewf/321532152/fsaявляется совпадением) с или без pathMatch: 'full'.
Кроме того, поскольку он соответствует всему, корневой путь также включен, что делает { path: '', redirectTo: 'welcome' }эту настройку полностью избыточной.
Как ни странно, вполне нормально иметь такую конфигурацию:
const routes: Routes = [
{
path: '**',
redirectTo: 'welcome'
},
{
path: 'welcome',
component: WelcomeComponent,
},
];
Если мы перейдем к /welcome, path: '**'будет совпадение и произойдет перенаправление на welcome. Теоретически это должно запустить бесконечный цикл перенаправлений, но Angular немедленно останавливает это (из-за защиты, о которой я упоминал ранее), и все это работает нормально.