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: fulldzieje, 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/articlesLiczy się tylko podstawowy adres URL ( ).
Angular dzieli adresy URL na segmenty . Segmenty /users/james/articlessą, oczywiście users, jamesi articles.
Konfiguracja routera to struktura drzewiasta z jednym węzłem głównym. Każdy Routeobiekt jest węzłem, który może mieć childrenwęzły, które z kolei mogą mieć inne childrenlub 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/cale router jest w stanie dopasować tylko jedno /a/blub drugie /a/b/c/d, wtedy nie ma dopasowania i aplikacja niczego nie wyrenderuje.
Wreszcie trasy redirectTozachowują 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.
prefixDopasowanie domyślnej ( ) ścieżki
Powodem tej nazwy prefixjest to, że taka konfiguracja trasy sprawdzi, czy skonfigurowana pathjest 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 Routeobiekt 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!
:otherpasuje do dowolnej wartości, więc jest zgodna. Jednak docelowy adres URL nie jest jeszcze w pełni dopasowany (nadal musimy dopasować jamesi articles), dlatego router szuka dzieci.
- Jedynym dzieckiem
:otherjest 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.
:userIDpasuje do wszystkiego, więc mamy dopasowanie do jamessegmentu. Jednak nadal nie jest to pełne dopasowanie, dlatego musimy szukać dziecka, które by pasowało articles.
- Widzimy, że
:userIDma trasę podrzędną articles, która daje nam pełne dopasowanie! W ten sposób aplikacja renderuje UserArticlesComponent.
Pełne fulldopasowanie adresu URL ( )
Przykład 1
Wyobraź sobie teraz, że usersobiekt 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 usersz pathMatch: fullnie 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/:userIDpathMatch: fulltylko z dopasowaniami w users/jamesten 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/articlesnadal nie ma sobie równych. Poszukajmy dzieci.
'permissions' !== 'james' - pominąć.
:userID'może pasować tylko do jednego segmentu james. Jest to jednak pathMatch: fulltrasa 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: fullkonfiguracja 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, Routektóry ma zdefiniowane a, redirectTozostanie 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 prefixstrategii 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/articlesOto 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-foundod razu znajduje dopasowanie dla . Aplikacja renderuje się NotFoundComponent.
Zastanów się teraz, co by się stało, gdyby userstrasa 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.
usersbędzie pasował do pierwszego segmentu adresu URL, ale konfiguracja trasy wymaga fulldopasowania, dlatego pomiń go.
'users/:userID'mecze users/james. articlesnadal nie jest dopasowany, ale ta trasa ma dzieci.
- Znajdziemy odpowiednik
articlesw 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ę
welcomedzieje 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 Routepowyż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/fsajest 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.