Zpracování cest
m.route
a m.request
používají koncept cesty (path). Ta slouží k vytvoření URL adresy, na kterou se aplikace přesměrovává, nebo ze které načítá data.
Typy cest
Existují dva základní typy cest: surové cesty (raw paths) a parametrizované cesty (parameterized paths).
- Surové cesty jsou prosté řetězce, které se používají přímo jako URL adresy. Neprovádí se žádná substituce ani rozdělování. Pouze se normalizují a na konec se připojí parametry.
- Parametrizované cesty umožňují vkládat hodnoty do URL adres, které jsou automaticky escapovány pro větší pohodlí a ochranu proti URL injekci.
Pro funkci m.request
to mohou být prakticky jakékoli URL adresy, ale pro routes pouze absolutní názvy cest URL bez schémat a domén.
Parametry cesty
Parametry cesty jsou samy o sobě poměrně jednoduché. Vyskytují se ve dvou formách:
:foo
- Toto vloží hodnotuparams.foo
do URL, přičemž ji nejprve escapuje.:foo...
- Toto vloží surovou cestuparams.foo
do URL bez escapování.
Možná se ptáte, co objekt params
představuje. Je to jednoduše objekt params
buď v m.route.set(path, params)
, nebo v m.request({url, params})
.
Při definování rout pomocí m.route(root, defaultRoute, routes)
můžete tyto parametry použít k extrahování hodnot z URL. Fungují v podstatě stejně jako při vytváření cest, pouze v opačném směru.
// Upravit jednu položku
m.route(document.body, '/edit/1', {
'/edit/:id': {
view: function () {
return [m(Menu), m('h1', 'Editing user ' + m.route.param('id'))];
},
},
});
// Upravit položku podle cesty
m.route(document.body, '/edit/pictures/image.jpg', {
'/edit/:file...': {
view: function () {
return [m(Menu), m('h1', 'Editing file ' + m.route.param('file'))];
},
},
});
V prvním příkladu, pokud přejdete na výchozí routu, m.route.param("id")
by vracelo "1"
a v druhém příkladu m.route.param("file")
by vracelo pictures/image.jpg
.
Parametry cesty mohou být odděleny znaky /
, -
nebo .
. To umožňuje vytvářet dynamické segmenty cesty a poskytuje větší flexibilitu než pouhý název cesty. Například byste mohli porovnávat routy jako "/edit/:name.:ext"
pro úpravy na základě přípony souboru nebo "/:lang-:region/view"
pro lokalizovanou routu.
Parametry cesty fungují stylem "greedy": pokud máme deklarovanou routu "/edit/:name.:ext"
a přejdeme na /edit/file.test.png
, extrahované parametry budou {name: "file.test", ext: "png"}
, a ne {name: "file", ext: "test.png"}
. Stejně tak, pokud máme "/route/:path.../view/:child..."
a přejdeme na /route/foo/view/bar/view/baz
, extrahované parametry budou {path: "foo/view/bar", child: "baz"}
.
Normalizace parametrů
Parametry cesty, které jsou vloženy do URL, se automaticky odstraňují z řetězce dotazu (query string), aby se zjednodušila a zachovala čitelnost URL. Například následující kód odešle serverový požadavek GET /api/user/1/connections?sort=name-asc
, přičemž vynechá duplicitní id=1
v URL.
m.request({
url: 'https://example.com/api/user/:userID/connections',
params: {
userID: 1,
sort: 'name-asc',
},
});
Můžete také explicitně zadat parametry přímo v řetězci dotazu, například takto, což je ekvivalentní výše uvedenému:
m.request({
url: 'https://example.com/api/user/:userID/connections?sort=name-asc',
params: {
userID: 1,
},
});
Samozřejmě můžete obojí kombinovat. Následující kód odešle požadavek na GET /api/user/1/connections?sort=name-asc&first=10
.
m.request({
url: 'https://example.com/api/user/:userID/connections?sort=name-asc',
params: {
userID: 1,
first: 10,
},
});
Tato vlastnost se vztahuje i na porovnávání tras: můžete porovnávat routu s explicitními parametry v řetězci dotazu. Odpovídající parametr se zachová pro snadný přístup, takže k němu můžete přistupovat přes parametry vnode nebo pomocí m.route.param
. Ačkoli je to možné, obecně se to nedoporučuje. Pro definici stránek byste měli upřednostňovat cesty. Může to být užitečné, pokud potřebujete vygenerovat mírně odlišné zobrazení pro specifický typ souboru, ale z logického hlediska se jedná o parametr dotazu, a ne o samostatnou stránku.
// Poznámka: toto se obecně *nedoporučuje* - měli byste upřednostňovat cesty pro deklarace rout,
// nikoli řetězce dotazu.
m.route(document.body, '/edit/1', {
'/edit?type=image': {
view: function () {
return [m(Menu), m('h1', 'Editing photo')]; // Úprava fotografie
},
},
'/edit': {
view: function () {
return [m(Menu), m('h1', 'Editing ' + m.route.param('type'))]; // Úprava typu
},
},
});
Parametry dotazu se implicitně přijímají - nemusíte je explicitně definovat, abyste je mohli použít. Můžete porovnávat na základě existující hodnoty, jako v "/edit?type=image"
, ale nemusíte používat "/edit?type=:type"
k přijetí hodnoty. Ve skutečnosti by Mithril.js s tím zacházel, jako byste se pokoušeli doslova porovnat s m.route.param("type") === ":type"
, což pravděpodobně nechcete. Jednoduše řečeno, použijte m.route.param("key")
nebo atributy komponenty tras ke čtení parametrů dotazu.
Normalizace cesty
Analyzované cesty jsou vždy vraceny s odstraněnými duplicitními parametry a nadbytečnými lomítky a vždy začínají lomítkem. Tyto drobné rozdíly mohou komplikovat routing a zpracování cest. Mithril.js interně normalizuje cesty pro routing, ale přímo nezpřístupňuje aktuální, normalizovanou routu. (Můžete ji vypočítat pomocí m.parsePathname(m.route.get()).path
.)
Když jsou parametry během porovnávání deduplikovány, parametry v řetězci dotazu mají přednost před parametry v názvu cesty a parametry směrem ke konci URL mají přednost před parametry blíže k začátku URL.
Escapování cesty
Existují některé znaky, které, pokud je chcete použít doslova, musíte escapovat. Funkce encodeURIComponent
tyto znaky (a další) kóduje. Při substituci parametrů a přidávání parametrů dotazu se automaticky použije toto kódování. Zde jsou ty, které Mithril.js interpretuje:
:
=%3A
/
=%2F
(vyžadováno pouze v cestách)%
=%25
?
=%3F
(vyžadováno pouze v cestách)#
=%23
Samozřejmě, existují i další znaky, které musíte escapovat podle specifikace URL, jako jsou mezery. Ale jak již bylo uvedeno, encodeURIComponent
to dělá za vás a Mithril.js to implicitně používá, když substituujete parametry. Starat se o to musíte pouze v případě, že explicitně zadáváte parametry, například v m.request("https://example.com/api/user/User%20Name/:field", {params: {field: ...}})
.