Yönlendirme
Rota Tablosu
RouteItem alanları, iç içe rotalar, redirect ve alias, yol parametreleri, rota tablosunu sorgulama, tembel rotalar ve geliştirme kipindeki rota denetimi.
Rota tanımı (RouteItem)
Rotalar bir RouteItem[] dizisidir. Her öğe bir yolu (path) bir bileşene (control) eşler. Örnek tablo RouteItem'ın sık kullanılan alanlarını bir arada gösterir: desen kısıtlı ve adlandırılmış bir rota ({id(\d+)}, name), bir layout alias'ı, varsayılanlı opsiyonel parametre ve yönlendirme (Yönlendirmeye Giriş sayfasındaki tablonun genişletilmiş hâli):
import type { RouteItem } from "@motifx/core";
import MainLayout from "./layouts/MainLayout";
import NotesLayout from "./layouts/NotesLayout";
import NoteEmptyPage from "./pages/NoteEmptyPage";
import NotePage from "./pages/NotePage";
import type { Folder } from "./services/notes";
const folder = (name: Folder): RouteItem => ({
path: `/${name}`,
control: NotesLayout,
meta: { folder: name },
childs: [
{ path: "/", control: NoteEmptyPage },
{ path: "/{id(\\d+)}", name: `${name}-note`, control: NotePage },
],
});
export const routes: RouteItem[] = [
{
path: "/",
control: MainLayout,
childs: [
{ path: "/", redirect: "/notes" },
{ ...folder("notes"), alias: "/notlar" },
folder("pinned"),
folder("archive"),
{ path: "/settings/{section?:appearance}", name: "settings", control: () => import("./pages/SettingsPage") },
{ path: "/n/{id}", redirect: "/notes/{id}" },
],
},
];
import MainLayout from "./layouts/MainLayout";
import NotesLayout from "./layouts/NotesLayout";
import NoteEmptyPage from "./pages/NoteEmptyPage";
import NotePage from "./pages/NotePage";
const folder = (name) => ({
path: `/${name}`,
control: NotesLayout,
meta: { folder: name },
childs: [
{ path: "/", control: NoteEmptyPage },
{ path: "/{id(\\d+)}", name: `${name}-note`, control: NotePage },
],
});
export const routes = [
{
path: "/",
control: MainLayout,
childs: [
{ path: "/", redirect: "/notes" },
{ ...folder("notes"), alias: "/notlar" },
folder("pinned"),
folder("archive"),
{ path: "/settings/{section?:appearance}", name: "settings", control: () => import("./pages/SettingsPage") },
{ path: "/n/{id}", redirect: "/notes/{id}" },
],
},
];
Bu alanların etkisi:
- Desene uymayan segment rotayla eşleşmez:
/notes/3eşleşir,/notes/abceşleşmez vefallbacks.notFoundgösterilir. nameverilen rotanın yoluhref/navigateByNameile üretilir:app.router.href("archive-note", { id: 7 })→/archive/7.- Alias aynı rotayı ikinci bir adresle açar ve adres çubuğunda alias kalır:
/notlar/3. - Opsiyonel parametre adreste yoksa varsayılanını alır:
/settings'teparams.section"appearance",/settings/notes'ta"notes". redirectdizesindeki{id}eşleşen parametreyle dolar:/n/3→/notes/3.
RouteItem alanları
| Alan | Açıklama |
|---|---|
path |
Rota yolu. Parametreler {name} biçiminde. Layout ve varsayılan çocuk için '/'; her çocuk yolu / ile başlar (geliştirme kipinde aksi MJX311 ile uyarılır). Aynı derinlikte statik segment parametreden önce gelir (/archive, /{slug}'ı yener). |
control |
Rota bileşeni. Bileşen sınıfı, hazır bileşen örneği, () => Component, Options API fabrikası, () => import(...) (lazy) veya Promise olabilir. Yalnızca redirect tanımlı rotada zorunlu değildir. Hazır örnek (ya da örneğe çözülen Promise) verilen rota keepAlive gibi davranır: örnek bir kez kurulur, ayrılırken outlet'ten ayrılır, dönüşte aynı örnek geri bağlanır, parametre değişiminde yeniden kurulmaz (onUpdate çalışır); app.router.evict() bu örneği serbest bırakmaz, app.dispose() eder. Örnek serbest bırakılmışken rotaya girilirse sayfa kurulamaz: MJX304 raporlanır (nedeni MJX318) ve hata rotası gösterilir; her girişte taze durum isteyen sayfa sınıf ya da fabrika verir. |
childs |
Alt rotalar. Tanımlıysa bu rota bir layout rotasıdır. |
name |
Rotaya isimle erişim için (opsiyonel); href ve navigateByName bu adı kullanır. |
meta |
Guard ve kancaların kullanabileceği serbest veri ({ requiresAuth: true, title: '...' }). Eşleşen zincirdeki (layout → çocuk) meta nesneleri birleştirilir; layout'a yazılan requiresAuth çocuklarında da görünür. Örnekte meta.folder layout rotasına yazılır, altındaki not rotasında da okunur. |
extend |
Rotaya iliştirilen ekstra veri; meta gibi zincir boyunca birleştirilir. extend.targetOutlet rotanın bileşeninin yerleşeceği adlandırılmış RouterView'ı seçer (bkz. RouterView). |
keepAlive |
true ise bileşen örneği korunur: ayrılırken outlet'ten ayrılır ve önbelleğe alınır (onDeactivated), geri dönüşte aynı örnek aynı konuma yeniden bağlanır (onActivated); ikisi de sayfanın görünür alt bileşenlerine iletilir. Önbellek app.router.evict(ad \| rota) (argümansız: hepsi; o an ekranda olan örnek atlanır) ya da app.dispose() ile boşaltılır. |
redirect |
Bu rotaya gelindiğinde başka yola yönlendirir: {param} yer tutuculu yol dizesi ya da (to) => yol fonksiyonu. Ayrıntı: Yönlendirme ve alias. |
alias |
Aynı rotaya açılan ek yol(lar); adres çubuğunda alias kalır. Ayrıntı: Yönlendirme ve alias. |
validate(e) |
Eşleşme sırasında { uri, key, routes, params } ile çağrılır; false döndürürse bu rota eşleşmiş sayılmaz (başka bir rota ya da fallbacks.notFound devreye girer). Zincirdeki her rotanın validate'i çalışır. key rotanın adı, yoksa tam yolu (alias eşleşmesinde de kendi yolu); routes aynı kuralla anahtarlanmış rota tablosu (Map): routes.get(e.key) doğrulanan rotadır, başka bir rotaya adı ya da tam yoluyla ulaşılır. |
onShow(component) |
Rotanın bileşeni kendi RouterView'ına her yerleştirildiğinde, bileşen örneğiyle çağrılır: ilk gösterim, parametre değişiminde yeniden oluşturma, keepAlive önbelleğinden dönüş, RouterView'ı yeniden kurulunca yeniden yerleşme. Layout rotaları için de çağrılır; gezinme boyunca yerinde kalan layout için tekrar çağrılmaz. Kancanın fırlattığı hata MJX306 koduyla raporlanır, gezinmeyi durdurmaz. |
Gezinmeye bağlı rota kancaları (onEntering, onEnter, onLeave, onUpdate) Rota Kancaları ve Guard'lar sayfasında anlatılır.
Yönlendirme ve alias
Örnekteki /n/{id} dize biçiminde bir yönlendirmedir. Hedef bir hesaba bağlıysa fonksiyon verilir:
const shortcuts: RouteItem[] = [
{ path: "/n/{id}", redirect: "/notes/{id}" },
{ path: "/find/{q}", redirect: (to) => "/notes?q=" + encodeURIComponent(to.params.q) },
];
const shortcuts = [
{ path: "/n/{id}", redirect: "/notes/{id}" },
{ path: "/find/{q}", redirect: (to) => "/notes?q=" + encodeURIComponent(to.params.q) },
];
redirect
- Dize biçiminde
{param}yer tutucuları eşleşen parametrelerle dolar. Kaynak adresteki sorgu dizesi (?…) ve#…, hedef kendi sorgusunu/#'ını içermiyorsa hedefe taşınır:/n/3?from=mail→/notes/3?from=mail. - Fonksiyon biçimi
{ path, params, meta }alır; döndürdüğü yol olduğu gibi kullanılır. - Yönlendirme eşleşmeden hemen sonra,
onLeaveveuseGuardguard'larından önce uygulanır; guard'lar ve kancalar yalnızca hedef rota için çalışır. Kaynak rotanın bileşeni hiç oluşturulmaz. - Zincir izlenir (
/a→/b→/c). 10 adımı aşan ya da daha önce geçilen bir yola dönen yönlendirme durdurulur, istenen adrestefallbacks.errorsayfası gösterilir ve geliştirme modunda konsolaMJX303uyarısı yazılır. - Tarayıcı geçmişine yalnızca hedef girer. Adres çubuğu zaten kaynak yolu gösteriyorsa (ilk yükleme, geri/ileri) kayıt
replaceile değiştirilir; böylece "geri" tuşu yönlendirmeye takılmaz. - Hedefin nereden geldiği
to.redirectedFrom(guard veonLeavebağlamı) veonRouterChangedyükündekiredirectedFromalanıyla okunur. - Yalnızca eşleşen yaprak rotanın
redirect'i uygulanır. Bir layout'un'/'varsayılan çocuğu varsa layout yolunda eşleşen yaprak o çocuktur; bu durumda layout'a yazılanredirectçalışmaz, yönlendirmeyi varsayılan çocuğa yazın. Örnekteki kök rota bunu yapar:/adresinde yönlendiren,MainLayout'un'/'çocuğudur.
alias
- Alias,
pathile aynı kuralla ebeveyn yoluna eklenir (/notesaltındakialias: '/detail/{id}'→/notes/detail/{id}). Parametreler alias kalıbından okunur. - Layout'un alias'ı altında çocukları da açılır: örnekte
/notlar/5→NotePage. - Alias ile asıl yol aynı rotadır: aralarında aynı parametrelerle geçişte bileşen korunur; parametreler değişirse her parametre değişiminde olduğu gibi
onUpdateçalışır ve sayfa yeniden kurulur (keepAlive: truekorur).keepAliveönbelleği de ortaktır. - Bir alias başka bir rotanın asıl yoluyla çakışırsa asıl yol kazanır. Geliştirme kipindeki denetim; alias'ın kendi yoluna eşit olmasında (
MJX315), iki rotanın aynı alias'ı kullanmasında (MJX316) ve çocuk alias'ında/öneki eksikliğinde (MJX314) uyarır. app.router.fullPatheşleşen kalıbı (alias'ta alias kalıbını),app.router.aliasOfasıl kalıbı verir (alias değilsenull):/notlar/5'te/notlar/{id(\d+)}ve/notes/{id(\d+)}.navigateByNamevehrefher zaman asıl yolu üretir.RouterLinksınıfları URL'ye bakar:/notlar'daykento="/notes"linki aktif sayılmaz.
Yol parametreleri
Parametreler {name} sözdizimiyle tanımlanır:
| Sözdizimi | Anlam |
|---|---|
{id} |
Zorunlu parametre. |
{id:1} |
Zorunlu; 1 yalnızca href / navigateByName yol üretirken değer verilmezse kullanılır (/h/{id:1} kalıbı /h adresiyle eşleşmez). |
{id?} |
Opsiyonel. |
{id?:5} |
Opsiyonel, varsayılan 5: adreste yoksa params.id '5' olur. |
{id(\d+)} |
Desen kısıtı: segment yalnız parantez içindeki düzenli ifadeye uyarsa eşleşir (büyük/küçük harf duyarsız; desendeki yakalayan gruplar yok sayılır; ? ve : desenin parçasıdır). ? ve varsayılanla birleşir: {id(\d+)?:1}. Desen tek segmente uygulanır, içinde / olamaz. JavaScript dizesinde ters bölü iki kez yazılır: "/{id(\\d+)}". |
{path+} |
Bir ya da daha çok segment: /files/a/b/c için params.path 'a/b/c' olur (düz metin; her segment ayrı çözülür, parçalar gerekirse split('/')). href için 'a/b' ya da ['a','b'] verilir, segmentler ayrı kodlanır. Desenle birleşir, desen her segmente uygulanır: {ids(\d+)+}. |
{path*} |
{path+} gibi, ama hiç segment olmayabilir ({path?} gibi opsiyonel, :varsayılan alır). |
Süslü parantez dışındaki : ve segmentin kalanı kalıptan düşer (/user/:id → /user/, hiçbir adresle eşleşmez); geliştirme kipinde denetim MJX319 ile uyarır.
Sıralamada {…+} ya da {…*} içeren rota, aynı derinlikte ve aynı statik sayısındaki rotalardan sonra gelir: /f/{a}/{b} /f/{rest+}'ten önce; /docs/{rest+} statik segmentiyle /{a}/{b}'den önce. Kullanılamayan desen (derlenmeyen, ( kapanmayan ya da / içeren) için denetim geliştirme kipinde MJX320 ile uyarır.
href, navigateByName ve redirect dizesi {…} yer tutucularını doldurur; değerler encodeURIComponent ile kodlanır (href('tag', { name: 'a/b' }) → /tags/a%2Fb, { name: 'çay' } → /tags/%C3%A7ay).
Parametrelere gezinme bağlamından/router'dan erişilir:
import { useNavigation } from "@motifx/core";
const nav = useNavigation();
const noteId = Number(nav.params.id);
import { useNavigation } from "@motifx/core";
const nav = useNavigation();
const noteId = Number(nav.params.id);
params sorgu dizesi değerlerini de içerir. Yol parametreleri gibi sorgu değerleri de dizedir ve yüzde kodlaması çözülmüş olarak gelir (/notes/5?tab=history → { id: '5', tab: 'history' }, /tags/%C3%A7ay?q=a%20b → { name: 'çay', q: 'a b' }); yolda + düz karakterdir, sorguda boşluktur; true, null, 2025-10-27 ya da {"a":1} gibi değerler de metin kalır. Sayı, boolean ya da tarih gerekiyorsa değeri kendiniz çevirin (Number(params.id)). Tekrarlanan anahtar (?tag=is&tag=ev) dizge dizisi olur (['is', 'ev']). Aynı adda yol parametresi sorgu değerini ezer. #… kısmı hiçbir zaman params'a girmez.
router.uri, onRouterChanged olayının uri'si, middleware ctx.uri'si ve guard'ın to.path'i adres biçimindedir: yüzde kodlu, adres çubuğuyla aynı (/tags/%C3%A7ay). Göstermek için decodeURIComponent, değer için params kullanın. navigate, RouterLink'in to'su ve onActive/onExact yolu ham (/tags/çay) ya da kodlu yazılabilir; ikisi aynı adrese gider ve aynı bağlantıyı etkin yapar.
Sorgu yalnızca gidilen adresten okunur: history modunda adreste ? yoksa params sorgu değeri içermez (önceki sayfanın sorgusu taşınmaz). hash/file modunda #'ten önceki sorgu (/?x=1#/a) sayfa düzeyindedir; kendi sorgusu olmayan her rotada params'a gelir, rotanın kendi sorgusu (#/b?z=3) varsa onun yerine o kullanılır.
Rota tablosunu sorgulama — resolve, href, routes
app.router gezinmeden rota tablosunu sorgulamak için üç üye taşır:
// Bir adres hangi rotaya eşleşir? (gezinmez, adres çubuğuna dokunmaz)
const { chain, result } = app.router.resolve("/notes/5");
if (result.ok) console.log(result.route?.name, result.params.id, result.meta.folder); // "notes-note" "5" "notes"
chain; // ['/', '/notes', '/5']
result.chain.map((r) => r.path); // ['/', '/notes', '/{id(\\d+)}']: kökten rotaya tanımlar
// Tanım sırasıyla bütün rotalar (takma adlar hariç); menü ya da site haritası üretmek için
const paths = app.router.routes.map((r) => r.fullPath);
// Bir adres hangi rotaya eşleşir? (gezinmez, adres çubuğuna dokunmaz)
const { chain, result } = app.router.resolve("/notes/5");
if (result.ok) console.log(result.route?.name, result.params.id, result.meta.folder); // "notes-note" "5" "notes"
chain; // ['/', '/notes', '/5']
result.chain.map((r) => r.path); // ['/', '/notes', '/{id(\\d+)}']: kökten rotaya tanımlar
// Tanım sırasıyla bütün rotalar (takma adlar hariç); menü ya da site haritası üretmek için
const paths = app.router.routes.map((r) => r.fullPath);
Adlandırılmış rotanın yolu href ile üretilir; RouterLink to, menü ve breadcrumb için. Örnekte bağlantının hedefi adlandırılmış rotadan üretilir (nav, useNavigation()'ın döndürdüğü router'dır):
<RouterLink to={nav.href(`${folder}-note`, { id: note.id })}>{note.title}</RouterLink>
const link = motifComponent(RouterLink, {
to: nav.href(`${folder}-note`, { id: note.id }),
childs: [motifComponent("text", (node: ComponentBase) => node.bindings.add("textContent", note, "title"))],
});
<RouterLink to={nav.href(`${folder}-note`, { id: note.id })}>{note.title}</RouterLink>
const link = motifComponent(RouterLink, {
to: nav.href(`${folder}-note`, { id: note.id }),
childs: [motifComponent("text", (node) => node.bindings.add("textContent", note, "title"))],
});
| Üye | Döndürür |
|---|---|
resolve(uri) |
RouteResolution: { chain, result }. chain, app.router.chain ile aynı biçimdedir (string[], her rotanın parametreleri doldurulmuş kendi yolu). result, o adrese gidilince navigate'in döndürdüğü ResolveResult'tır: { ok, uri, fullPath, route, chain, params, meta, extend, aliasOf }; result.chain kökten rotaya kadar olan rota tanımlarıdır (RouteItem[]). Eşleşme yoksa result.ok false, chain []. Guard, middleware ve redirect çalışmaz. |
href(ad, params?) |
Adlandırılmış rotanın parametreleri doldurulmuş yolu (navigateByName ile aynı hesap). 0 ve false değerleri yazılır; undefined, null ve '' verilen ya da hiç verilmeyen parametrede kalıbın varsayılanı kullanılır (varsayılan yoksa o segment yazılmaz). Kalıpta olmayan parametreler yazılmaz; sorgu gerekiyorsa üretilen yola eklenir (href("notes-note", { id: 3 }) + "?tab=history"). Ad yoksa MJX302 fırlatır. |
routes |
RouteInfo[]: { fullPath, name, meta, route, chain }. Layout ve varsayılan çocuk ayrı öğelerdir; chain kökten bu rotaya kadar olan rota tanımlarıdır. |
Lazy (tembel) yükleme
control alanında () => import(...) kullanmak, rota bileşenini yalnızca ihtiyaç anında yükler ve otomatik kod bölme (code splitting) sağlar. Bu biçimde verilen sayfa ayrı bir parçaya (chunk) ayrılır ve rotaya ilk gidildiğinde indirilir:
const settings: RouteItem = { path: "/settings/{section?:appearance}", name: "settings", control: () => import("./pages/SettingsPage") };
const settings = { path: "/settings/{section?:appearance}", name: "settings", control: () => import("./pages/SettingsPage") };
Yüklenen modül sayfayı default olarak dışa aktarmalıdır. Adlandırılmış dışa aktarım için eşleyin: control: () => import("./pages/SettingsPage").then((m) => m.SettingsPage). default dışa aktarımı olmayan modül ya da bileşen olmayan başka bir nesneyle sayfa kurulamaz: MJX304 raporlanır (nedeni MJX127) ve fallbacks.error gösterilir.
fallbacks.notFound ve fallbacks.error de aynı lazy biçimi destekler.
Rotanın import()'u yükleme görünümü ya da yeniden deneme kullanmaz. Bir sayfanın içindeki ağır parçayı tembel yüklemek, yüklenirken bir görünüm göstermek ve mobil ağda yeniden denemek için Lazy bileşeni kullanılır (bkz. Yeniden deneme).
Geliştirme kipinde rota denetimi
app.useDevelopment(true) useRouter'dan önce çağrıldığında rota tablosu kurulurken denetlenir; sorunlu tanım konsola uyarı olarak yazılır, router çalışmaya devam eder:
| Kod | Ne zaman |
|---|---|
MJX310 |
Rota yolu boş (''); varsayılan çocuk için '/' yazılır. |
MJX311 |
Çocuk rotanın yolu / ile başlamıyor ('notes'). |
MJX312 |
Çocuk rota ebeveyniyle aynı tam yola çıkıyor (varsayılan çocuk '/' hariç). |
MJX313 |
Birden çok rota aynı tam yola çıkıyor. |
MJX314 |
Çocuk rotanın alias'ı / ile başlamıyor. |
MJX315 |
Alias rotanın kendi yoluna eşit. |
MJX316 |
Birden çok rota aynı alias'ı kullanıyor. |
MJX319 |
Yolda ya da alias'ta süslü parantez dışında : var (/user/:id). |
MJX320 |
Parametre deseni kullanılamıyor: derlenmiyor, ( kapanmıyor ya da / içeriyor. |
Sonraki adım
Rota bileşenlerinin ekranda nereye yerleştiğini öğrenmek için RouterView bölümüne geçin.