Chociaż technicznie poprawne, inne odpowiedzi skorzystałyby na wyjaśnieniu dopasowania adresu URL do trasy w Angular. Nie sądzę, że możesz w pełni (przepraszam za kalambur) zrozumieć, co się pathMatch: full
dzieje, jeśli nie wiesz, jak działa router.
Najpierw zdefiniujmy kilka podstawowych rzeczy. Użyjemy tego adresu jako przykład: /users/james/articles?from=134#section
.
Może to być oczywiste, ale najpierw zwróćmy uwagę, że parametry zapytania ( ?from=134
) i fragmenty ( #section
) nie odgrywają żadnej roli w dopasowywaniu ścieżek . /users/james/articles
Liczy się tylko podstawowy adres URL ( ).
Angular dzieli adresy URL na segmenty . Segmenty /users/james/articles
są, oczywiście users
, james
i articles
.
Konfiguracja routera to struktura drzewiasta z jednym węzłem głównym. Każdy Route
obiekt jest węzłem, który może mieć children
węzły, które z kolei mogą mieć inne children
lub być węzłami-liśćmi.
Celem routera jest znalezienie gałęzi konfiguracji routera , zaczynającej się od węzła głównego, która pasowałaby dokładnie do wszystkich (!!!) segmentów adresu URL. To jest kluczowe! Jeśli Angular nie znajdzie gałęzi konfiguracji trasy, która pasowałaby do całego adresu URL - ni mniej, ni więcej - niczego nie wyrenderuje .
Np. Jeśli docelowy adres URL to, /a/b/c
ale router jest w stanie dopasować tylko jedno /a/b
lub drugie /a/b/c/d
, wtedy nie ma dopasowania i aplikacja niczego nie wyrenderuje.
Wreszcie trasy redirectTo
zachowują się nieco inaczej niż zwykłe trasy i wydaje mi się, że byłyby jedynym miejscem, z którego naprawdę ktoś chciałby skorzystać pathMatch: full
. Ale do tego dojdziemy później.
prefix
Dopasowanie domyślnej ( ) ścieżki
Powodem tej nazwy prefix
jest to, że taka konfiguracja trasy sprawdzi, czy skonfigurowana path
jest prefiksem pozostałych segmentów adresu URL. Jednak router jest w stanie dopasować tylko pełne segmenty , co sprawia, że to nazewnictwo jest nieco mylące.
W każdym razie, powiedzmy, że to jest nasza konfiguracja routera na poziomie głównym:
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,
},
],
},
],
},
];
Zauważ, że każdy pojedynczy Route
obiekt używa tutaj domyślnej strategii dopasowywania, czyli prefix
. Ta strategia oznacza, że router dokonuje iteracji po całym drzewie konfiguracji i próbuje dopasować go do docelowego adresu URL segment po segmencie, aż adres URL zostanie w pełni dopasowany . Oto, jak można by to zrobić w tym przykładzie:
- Iteruj po tablicy głównej, szukając dokładnego dopasowania dla pierwszego segmentu adresu URL -
users
.
'products' !== 'users'
, więc pomiń tę gałąź. Zauważ, że używamy sprawdzania równości, a nie .startsWith()
lub .includes()
- liczą się tylko dopasowania pełnego segmentu!
:other
pasuje do dowolnej wartości, więc jest zgodna. Jednak docelowy adres URL nie jest jeszcze w pełni dopasowany (nadal musimy dopasować james
i articles
), dlatego router szuka dzieci.
- Jedynym dzieckiem
:other
jest tricks
, które jest !== 'james'
, więc nie pasuje.
- Następnie Angular wraca do tablicy głównej i stamtąd kontynuuje.
'user' !== 'users
, pomiń gałąź.
'users' === 'users
- segment pasuje. Jednak nie jest to jeszcze pełne dopasowanie, dlatego musimy szukać dzieci (tak samo jak w kroku 3).
'permissions' !== 'james'
, pomiń to.
:userID
pasuje do wszystkiego, więc mamy dopasowanie do james
segmentu. Jednak nadal nie jest to pełne dopasowanie, dlatego musimy szukać dziecka, które by pasowało articles
.
- Widzimy, że
:userID
ma trasę podrzędną articles
, która daje nam pełne dopasowanie! W ten sposób aplikacja renderuje UserArticlesComponent
.
Pełne full
dopasowanie adresu URL ( )
Przykład 1
Wyobraź sobie teraz, że users
obiekt konfiguracyjny trasy wyglądał następująco:
{
path: 'users',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
Zwróć uwagę na użycie pathMatch: full
. Gdyby tak było, kroki 1-5 byłyby takie same, jednak krok 6 byłby inny:
'users' !== 'users/james/articles
- segment nie pasuje, ponieważ konfiguracja ścieżki users
z pathMatch: full
nie pasuje do pełnego adresu URL, czyli users/james/articles
.
- Ponieważ nie ma dopasowania, pomijamy tę gałąź.
- W tym momencie dotarliśmy do końca konfiguracji routera bez znalezienia dopasowania. Aplikacja nic nie wyświetla .
Przykład 2
A co by było, gdybyśmy zamiast tego mieli to:
{
path: 'users/:userID',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
}
users/:userID
pathMatch: full
tylko z dopasowaniami w users/james
ten sposób ponownie nie pasuje, a aplikacja nic nie wyświetla.
Przykład 3
Rozważmy to:
{
path: 'users',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
W tym przypadku:
'users' === 'users
- segment pasuje, ale james/articles
nadal nie ma sobie równych. Poszukajmy dzieci.
'permissions' !== 'james'
- pominąć.
:userID'
może pasować tylko do jednego segmentu james
. Jest to jednak pathMatch: full
trasa i musi pasować james/articles
(cały pozostały adres URL). Nie jest w stanie tego zrobić i dlatego nie pasuje (więc pomijamy tę gałąź)!
- Ponownie nie znaleźliśmy żadnego dopasowania dla adresu URL, a aplikacja nic nie renderuje .
Jak być może zauważyłeś, pathMatch: full
konfiguracja zasadniczo mówi tak:
Ignoruj moje dzieci i dopasowuj tylko do mnie. Jeśli nie jestem w stanie samodzielnie dopasować wszystkich pozostałych segmentów adresów URL, przejdź dalej.
Przekierowania
Każdy, Route
który ma zdefiniowane a, redirectTo
zostanie dopasowany do docelowego adresu URL według tych samych zasad. Jedyna różnica polega na tym, że przekierowanie jest stosowane natychmiast po dopasowaniu segmentu . Oznacza to, że jeśli trasa przekierowująca używa prefix
strategii domyślnej , częściowe dopasowanie wystarczy, aby spowodować przekierowanie . Oto dobry przykład:
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,
},
],
},
];
/users/james/articles
Oto co by się stało w przypadku naszego początkowego adresu URL ( ):
'not-found' !== 'users'
- pomiń to.
'users' === 'users'
- mamy dopasowanie.
- To dopasowanie ma
redirectTo: 'not-found'
, które jest stosowane natychmiast .
- Docelowy adres URL zmieni się na
not-found
.
- Router ponownie rozpoczyna dopasowywanie i
not-found
od razu znajduje dopasowanie dla . Aplikacja renderuje się NotFoundComponent
.
Zastanów się teraz, co by się stało, gdyby users
trasa miała również 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'
- pomiń to.
users
będzie pasował do pierwszego segmentu adresu URL, ale konfiguracja trasy wymaga full
dopasowania, dlatego pomiń go.
'users/:userID'
mecze users/james
. articles
nadal nie jest dopasowany, ale ta trasa ma dzieci.
- Znajdziemy odpowiednik
articles
w dzieciach. Cały adres URL jest teraz dopasowany, a aplikacja renderuje się UserArticlesComponent
.
Pusta ścieżka ( path: ''
)
Pusta ścieżka jest trochę szczególnym przypadkiem, ponieważ może dopasować dowolny segment bez „konsumowania” go (więc jego elementy podrzędne musiałyby ponownie dopasować ten segment). Rozważmy ten przykład:
const routes: Routes = [
{
path: '',
children: [
{
path: 'users',
component: BadUsersComponent,
}
]
},
{
path: 'users',
component: GoodUsersComponent,
},
];
Powiedzmy, że próbujemy uzyskać dostęp /users
:
path: ''
będzie zawsze pasować, więc trasa będzie pasować. Jednak cały adres URL nie został dopasowany - nadal musimy dopasować users
!
- Widzimy, że jest dziecko
users
, które pasuje do pozostałego (i jedynego!) Segmentu i mamy pełne dopasowanie. Aplikacja renderuje się BadUsersComponent
.
Wróćmy teraz do pierwotnego pytania
OP użył tej konfiguracji routera:
const routes: Routes = [
{
path: 'welcome',
component: WelcomeComponent,
},
{
path: '',
redirectTo: 'welcome',
pathMatch: 'full',
},
{
path: '**',
redirectTo: 'welcome',
pathMatch: 'full',
},
];
Jeśli przechodzimy do głównego adresu URL ( /
), oto jak router mógłby to rozwiązać:
welcome
nie pasuje do pustego segmentu, więc pomiń go.
path: ''
pasuje do pustego segmentu. Ma pathMatch: 'full'
, co również jest zadowalające, ponieważ dopasowaliśmy cały adres URL (miał jeden pusty segment).
- Przekierowanie do się
welcome
dzieje i aplikacja się renderuje WelcomeComponent
.
A jeśli nie było pathMatch: 'full'
?
Właściwie należałoby się spodziewać, że całość będzie się zachowywać dokładnie tak samo. Jednak Angular wyraźnie zapobiega takiej konfiguracji ( { path: '', redirectTo: 'welcome' }
), ponieważ jeśli umieścisz to Route
powyżej welcome
, teoretycznie utworzyłoby to nieskończoną pętlę przekierowań. Więc Angular po prostu zgłasza błąd , przez co aplikacja w ogóle nie działała! ( https://angular.io/api/router/Route#pathMatch )
Właściwie, to nie ma zbyt wiele sensu do mnie, ponieważ kątowe także wdrożył ochronę przed takimi nieskończonych przekierowań - tylko biegnie pojedynczy przekierowanie za routing poziom! To zatrzymałoby wszystkie dalsze przekierowania (jak zobaczysz w poniższym przykładzie).
O co chodzi path: '**'
?
path: '**'
dopasuje absolutnie wszystko ( af/frewf/321532152/fsa
jest dopasowaniem) z lub bez pathMatch: 'full'
.
Ponadto, ponieważ pasuje do wszystkiego, dołączona jest również ścieżka główna, co czyni ją { path: '', redirectTo: 'welcome' }
całkowicie zbędną w tej konfiguracji.
Co zabawne, taka konfiguracja jest całkowicie w porządku:
const routes: Routes = [
{
path: '**',
redirectTo: 'welcome'
},
{
path: 'welcome',
component: WelcomeComponent,
},
];
Jeśli przejdziemy do /welcome
, path: '**'
nastąpi dopasowanie i nastąpi przekierowanie na powitanie. Teoretycznie powinno to zapoczątkować niekończącą się pętlę przekierowań, ale Angular natychmiast to zatrzymuje (ze względu na ochronę, o której wspomniałem wcześniej) i całość działa dobrze.