Sebbene tecnicamente corrette, le altre risposte trarrebbero vantaggio da una spiegazione della corrispondenza tra URL e route di Angular. Non penso che tu possa completamente (scusate il gioco di parole) capire cosa pathMatch: full
fa se non sai come funziona il router in primo luogo.
Definiamo prima alcune cose di base. Useremo questo URL, ad esempio: /users/james/articles?from=134#section
.
Può essere ovvio, ma prima facciamo notare che i parametri di query ( ?from=134
) e fragments ( #section
) non giocano alcun ruolo nella corrispondenza del percorso . Solo l'URL di base ( /users/james/articles
) è importante.
Angular divide gli URL in segmenti . I segmenti di /users/james/articles
sono, ovviamente users
, james
e articles
.
La configurazione del router è una struttura ad albero con un singolo nodo radice. Ogni Route
oggetto è un nodo, che può avere children
nodi, che a loro volta possono avere altri children
o essere nodi foglia.
L'obiettivo del router è trovare un ramo di configurazione del router , a partire dal nodo radice, che corrisponda esattamente a tutti (!!!) i segmenti dell'URL. Questo è fondamentale! Se Angular non trova un ramo di configurazione del percorso che potrebbe corrispondere all'intero URL - né più né meno - non renderà nulla .
Ad esempio, se l'URL di destinazione è /a/b/c
ma il router è in grado di corrispondere solo a /a/b
o /a/b/c/d
, allora non c'è corrispondenza e l'applicazione non visualizzerà nulla.
Infine, percorsi con redirectTo
comportano in modo leggermente diverso rispetto alle rotte normali, e mi sembra che sarebbero l'unico posto dove chiunque vorrebbe davvero usare pathMatch: full
. Ma ci arriveremo più tardi.
prefix
Corrispondenza del percorso predefinito ( )
Il ragionamento alla base del nome prefix
è che tale configurazione del percorso verificherà se il filepath
è un prefisso dei segmenti di URL rimanenti. Tuttavia, il router è in grado di abbinare solo segmenti completi , il che rende questa denominazione leggermente confusa.
Ad ogni modo, diciamo che questa è la nostra configurazione del router a livello di root:
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,
},
],
},
],
},
];
Nota che ogni singolo Route
oggetto qui utilizza la strategia di corrispondenza predefinita, che è prefix
. Questa strategia significa che il router itera sull'intero albero di configurazione e cerca di abbinarlo all'URL di destinazione segmento per segmento finché l'URL non viene completamente abbinato . Ecco come sarebbe fatto per questo esempio:
- Scorri l'array radice cercando una corrispondenza esatta per il primo segmento di URL -
users
.
'products' !== 'users'
, quindi salta quel ramo. Nota che stiamo usando un controllo di uguaglianza invece di un.startsWith()
o .includes()
- contano solo le corrispondenze di segmenti completi!
:other
corrisponde a qualsiasi valore, quindi è una corrispondenza. Tuttavia, l'URL di destinazione non è ancora completamente abbinato (dobbiamo ancora trovare la corrispondenzajames
e articles
), quindi il router cerca i bambini.
- L'unico figlio di
:other
è tricks
, che è!== 'james'
, quindi non una corrispondenza.
- Angular quindi torna indietro all'array radice e continua da lì.
'user' !== 'users
, salta ramo.
'users' === 'users
- il segmento corrisponde. Tuttavia, questa non è ancora una corrispondenza completa, quindi dobbiamo cercare i bambini (come nel passaggio 3).
'permissions' !== 'james'
, salta.
:userID
corrisponde a qualsiasi cosa, quindi abbiamo una corrispondenza per il james
segmento. Tuttavia questa non è ancora una corrispondenza completa, quindi dobbiamo cercare un bambino che corrisponda articles
.
- Possiamo vedere che
:userID
ha un percorso figlio articles
, che ci dà una corrispondenza completa! Quindi l'applicazione esegue il rendering UserArticlesComponent
.
full
Corrispondenza URL completa ( )
Esempio 1
Immagina ora che l' users
oggetto di configurazione del percorso abbia questo aspetto:
{
path: 'users',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
Nota l'utilizzo di pathMatch: full
. In tal caso, i passaggi 1-5 sarebbero gli stessi, tuttavia il passaggio 6 sarebbe diverso:
'users' !== 'users/james/articles
- il segmento non corrisponde perché la configurazione del percorso users
con pathMatch: full
non corrisponde all'URL completo, che è users/james/articles
.
- Poiché non c'è corrispondenza, stiamo saltando questo ramo.
- A questo punto siamo giunti alla fine della configurazione del router senza aver trovato una corrispondenza. L'applicazione non restituisce nulla .
Esempio 2
E se invece avessimo questo:
{
path: 'users/:userID',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
}
users/:userID
pathMatch: full
solo con fiammiferiusers/james
quindi è ancora una volta una non corrispondenza e l'applicazione non restituisce nulla.
Esempio 3
Consideriamo questo:
{
path: 'users',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
In questo caso:
'users' === 'users
- il segmento corrisponde, ma james/articles
rimane ancora senza corrispondenza. Cerchiamo bambini.
'permissions' !== 'james'
- Salta.
:userID'
può corrispondere solo a un singolo segmento, che sarebbe james
. Tuttavia, è una pathMatch: full
rotta e deve corrispondere james/articles
(l'intero URL rimanente). Non è in grado di farlo e quindi non è una corrispondenza (quindi saltiamo questo ramo)!
- Ancora una volta, non siamo riusciti a trovare alcuna corrispondenza per l'URL e l'applicazione non restituisce nulla .
Come avrai notato, una pathMatch: full
configurazione fondamentalmente dice questo:
Ignora i miei figli e abbina solo me. Se non sono in grado di abbinare personalmente tutti i segmenti di URL rimanenti , vai avanti.
Reindirizzamenti
Tutto ciò Route
che ha definito a redirectTo
verrà confrontato con l'URL di destinazione secondo gli stessi principi. L'unica differenza qui è che il reindirizzamento viene applicato non appena un segmento corrisponde . Ciò significa che se un percorso di reindirizzamento utilizza la prefix
strategia predefinita , una corrispondenza parziale è sufficiente per provocare un reindirizzamento . Ecco un buon esempio:
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,
},
],
},
];
Per il nostro URL iniziale ( /users/james/articles
), ecco cosa accadrebbe:
'not-found' !== 'users'
- saltalo.
'users' === 'users'
- abbiamo una corrispondenza.
- Questa corrispondenza ha un
redirectTo: 'not-found'
, che viene applicato immediatamente .
- L'URL di destinazione cambia in
not-found
.
- Il router inizia di nuovo la corrispondenza e trova subito una corrispondenza per
not-found
. L'applicazione esegue il rendering NotFoundComponent
.
Consideriamo ora cosa accadrebbe se il users
percorso avesse anche 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'
- saltalo.
users
corrisponderebbe al primo segmento dell'URL, ma la configurazione del percorso richiede una full
corrispondenza, quindi saltala.
'users/:userID'
partite users/james
. articles
non è ancora abbinato ma questo percorso ha dei bambini.
- Troviamo una corrispondenza per
articles
nei bambini. L'intero URL viene ora trovato e l'applicazione esegue il rendering UserArticlesComponent
.
Percorso vuoto ( path: ''
)
Il percorso vuoto è un po 'un caso speciale perché può abbinare qualsiasi segmento senza "consumarlo" (quindi i suoi figli dovrebbero corrispondere di nuovo a quel segmento). Considera questo esempio:
const routes: Routes = [
{
path: '',
children: [
{
path: 'users',
component: BadUsersComponent,
}
]
},
{
path: 'users',
component: GoodUsersComponent,
},
];
Diciamo che stiamo cercando di accedere /users
:
path: ''
corrisponderà sempre, quindi il percorso corrisponde. Tuttavia, l'intero URL non è stato trovato: dobbiamo ancora trovare una corrispondenzausers
!
- Possiamo vedere che c'è un figlio
users
, che corrisponde al segmento rimanente (e unico!) E abbiamo una corrispondenza completa. L'applicazione esegue il rendering BadUsersComponent
.
Ora torniamo alla domanda originale
L'OP ha utilizzato questa configurazione del router:
const routes: Routes = [
{
path: 'welcome',
component: WelcomeComponent,
},
{
path: '',
redirectTo: 'welcome',
pathMatch: 'full',
},
{
path: '**',
redirectTo: 'welcome',
pathMatch: 'full',
},
];
Se stiamo navigando all'URL di root ( /
), ecco come il router lo risolverà:
welcome
non corrisponde a un segmento vuoto, quindi saltalo.
path: ''
corrisponde al segmento vuoto. Ha un pathMatch: 'full'
, che è anche soddisfatto perché abbiamo trovato l'intero URL (aveva un singolo segmento vuoto).
- Viene eseguito un reindirizzamento a
welcome
e l'applicazione esegue il rendering WelcomeComponent
.
E se non ci fosse stato pathMatch: 'full'
?
In realtà, ci si aspetterebbe che l'intera faccenda si comporti esattamente allo stesso modo. Tuttavia, Angular impedisce esplicitamente tale configurazione ( { path: '', redirectTo: 'welcome' }
) perché se lo metti Route
sopra welcome
, teoricamente creerebbe un ciclo infinito di reindirizzamenti. Quindi Angular genera solo un errore , motivo per cui l'applicazione non funzionerebbe affatto! ( https://angular.io/api/router/Route#pathMatch )
Questo non ha davvero molto senso perché Angular ha implementato una protezione contro reindirizzamenti infiniti: esegue solo un singolo reindirizzamento per livello di instradamento.
Di cosa path: '**'
?
path: '**'
corrisponderà assolutamente a qualsiasi cosa ( af/frewf/321532152/fsa
è una corrispondenza) con o senza pathMatch: 'full'
, quindi non ha senso usare questa opzione di configurazione.
Inoltre, poiché corrisponde a tutto, è incluso anche il percorso di root, il che rende { path: '', redirectTo: 'welcome' }
ridondante in questa configurazione.
Stranamente, va benissimo avere questa configurazione:
const routes: Routes = [
{
path: '**',
redirectTo: 'welcome'
},
{
path: 'welcome',
component: WelcomeComponent,
},
];
Se navighiamo verso /welcome
, path: '**'
sarà una partita e un reindirizzamento al benvenuto avverrà. Questo dovrebbe dare il via a un ciclo infinito di reindirizzamenti, ma Angular lo interrompe immediatamente e il tutto funziona bene.