Yönlendirme
Bağlantılar
rel="router" bağlantıları, RouterLink ve herhangi bir bileşende rota sınıfları; JSX ile ve JSX'siz.
Uygulama içi bir bağlantıya tıklandığında sayfa yeniden yüklenmez; router adresi değiştirir ve rota zincirinin değişen halkasını kurar. Bunun için üç yol vardır: düz <a> etiketine rel="router" yazmak, aktif bağlantıyı sınıfla işaretleyen RouterLink bileşeni ve aynı sınıf mantığını herhangi bir bileşene açan enableRouterClassing.
rel="router" ile
Standart <a> etiketine rel="router" ekleyerek MotifJS'in tıklamayı yakalamasını ve tam sayfa yenilemeden gezinmesini sağlayın. href sabit bir yol ya da bir getter olabilir:
<a rel="router" href={`/${this.folder}`} class="button button--sm ghost only-narrow">‹ Geri</a>
<a rel="router" href="/notes" class="button">Tüm notlar</a>
<a rel="router" href={`/${folder()}`} class="button button--sm ghost only-narrow">‹ Geri</a>
<a rel="router" href="/notes" class="button">Tüm notlar</a>
const back = motifComponent("a", (a: ComponentBase) => {
a.attr.add({ rel: "router", href: () => `/${this.folder}` });
a.class.add("button button--sm ghost only-narrow");
a.controls.add(motifComponent("text", (node: ComponentBase) => node.setText("‹ Geri")));
});
const all = motifComponent("a", (a: ComponentBase) => {
a.attr.add({ rel: "router", href: "/notes" });
a.class.add("button");
a.controls.add(motifComponent("text", (node: ComponentBase) => node.setText("Tüm notlar")));
});
const back = motifComponent("a", (a: ComponentBase) => {
a.attr.add({ rel: "router", href: () => `/${folder()}` });
a.class.add("button button--sm ghost only-narrow");
a.controls.add(motifComponent("text", (node: ComponentBase) => node.setText("‹ Geri")));
});
const all = motifComponent("a", (a: ComponentBase) => {
a.attr.add({ rel: "router", href: "/notes" });
a.class.add("button");
a.controls.add(motifComponent("text", (node: ComponentBase) => node.setText("Tüm notlar")));
});
<a rel="router" href={`/${this.folder}`} class="button button--sm ghost only-narrow">‹ Geri</a>
<a rel="router" href="/notes" class="button">Tüm notlar</a>
<a rel="router" href={`/${folder()}`} class="button button--sm ghost only-narrow">‹ Geri</a>
<a rel="router" href="/notes" class="button">Tüm notlar</a>
const back = motifComponent("a", (a) => {
a.attr.add({ rel: "router", href: () => `/${this.folder}` });
a.class.add("button button--sm ghost only-narrow");
a.controls.add(motifComponent("text", (node) => node.setText("‹ Geri")));
});
const all = motifComponent("a", (a) => {
a.attr.add({ rel: "router", href: "/notes" });
a.class.add("button");
a.controls.add(motifComponent("text", (node) => node.setText("Tüm notlar")));
});
const back = motifComponent("a", (a) => {
a.attr.add({ rel: "router", href: () => `/${folder()}` });
a.class.add("button button--sm ghost only-narrow");
a.controls.add(motifComponent("text", (node) => node.setText("‹ Geri")));
});
const all = motifComponent("a", (a) => {
a.attr.add({ rel: "router", href: "/notes" });
a.class.add("button");
a.controls.add(motifComponent("text", (node) => node.setText("Tüm notlar")));
});
Fonksiyon bileşeninde notes FromService ile alınan servis, folder() klasörü döndüren yerel fonksiyondur.
rel başka değerlerle birlikte de verilebilir (rel="router nofollow"); router belirtecinin kümede olması yeter. data-router-link özniteliği de aynı işi görür. Ctrl/Meta/Shift/Alt ile yapılan tıklamalar, target'ı _self dışında olan bağlantılar ve history modunda başka origin'e giden adresler yakalanmaz. hash/file modunda href="#/archive" ve href="/archive" aynı yere gider. Yakalayıcı sayfanın belgesinde ve app.connectDocument ile bağlanan her belgede dinler; bir popup'a taşınmış içerikteki rel="router" bağlantısı o pencereyi yeniden yüklemez, sayfanın router'ını gezdirir.
RouterLink bileşeni
Aktif/eşleşme sınıflarını otomatik yöneten bir bağlantı bileşenidir: geçerli adres to ile eşleştikçe activeClass / exactClass sınıflarını ekler. Çocukları bağlantının içeriği olur; JSX'siz yazımda çocuklar childs ile, yalnız metin olan bağlantının metni text ile verilir:
<RouterLink to="/notes" activeClass="active">
Tüm notlar <span class="badge">{() => this.notes.count("notes")}</span>
</RouterLink>
<RouterLink to="/settings" activeClass="active">Ayarlar</RouterLink>
<RouterLink to="/notes" activeClass="active">
Tüm notlar <span class="badge">{() => notes.count("notes")}</span>
</RouterLink>
<RouterLink to="/settings" activeClass="active">Ayarlar</RouterLink>
const all = motifComponent(RouterLink, {
to: "/notes",
activeClass: "active",
childs: [
motifComponent("text", (node: ComponentBase) => node.setText("Tüm notlar ")),
motifComponent("span", (span: ComponentBase) => {
span.class.add("badge");
span.controls.add(motifComponent("text", (node: ComponentBase) => node.bindings.text(() => this.notes.count("notes"))));
}),
],
});
const settings = motifComponent(RouterLink, { to: "/settings", activeClass: "active", text: "Ayarlar" });
const all = motifComponent(RouterLink, {
to: "/notes",
activeClass: "active",
childs: [
motifComponent("text", (node: ComponentBase) => node.setText("Tüm notlar ")),
motifComponent("span", (span: ComponentBase) => {
span.class.add("badge");
span.controls.add(motifComponent("text", (node: ComponentBase) => node.bindings.text(() => notes.count("notes"))));
}),
],
});
const settings = motifComponent(RouterLink, { to: "/settings", activeClass: "active", text: "Ayarlar" });
<RouterLink to="/notes" activeClass="active">
Tüm notlar <span class="badge">{() => this.notes.count("notes")}</span>
</RouterLink>
<RouterLink to="/settings" activeClass="active">Ayarlar</RouterLink>
<RouterLink to="/notes" activeClass="active">
Tüm notlar <span class="badge">{() => notes.count("notes")}</span>
</RouterLink>
<RouterLink to="/settings" activeClass="active">Ayarlar</RouterLink>
const all = motifComponent(RouterLink, {
to: "/notes",
activeClass: "active",
childs: [
motifComponent("text", (node) => node.setText("Tüm notlar ")),
motifComponent("span", (span) => {
span.class.add("badge");
span.controls.add(motifComponent("text", (node) => node.bindings.text(() => this.notes.count("notes"))));
}),
],
});
const settings = motifComponent(RouterLink, { to: "/settings", activeClass: "active", text: "Ayarlar" });
const all = motifComponent(RouterLink, {
to: "/notes",
activeClass: "active",
childs: [
motifComponent("text", (node) => node.setText("Tüm notlar ")),
motifComponent("span", (span) => {
span.class.add("badge");
span.controls.add(motifComponent("text", (node) => node.bindings.text(() => notes.count("notes"))));
}),
],
});
const settings = motifComponent(RouterLink, { to: "/settings", activeClass: "active", text: "Ayarlar" });
Bağlantı bir <a> elemanıdır; başka bir etiket için el verilir. Prop'lar:
| Prop | Etki |
|---|---|
to |
Hedef yol. href olarak da yazılır; hash/file kipinde başına # eklenir (#/archive), böylece yeni sekmede açılan ya da kopyalanan bağlantı doğru adrese gider. href bağlantı kurulurken router'ın kipine göre yazılır. |
showHref |
false ise href yazılmaz; tıklama yine gezinir. |
target |
Öznitelik olarak yazılır. _self dışındaki bir değerde tıklama tarayıcıya bırakılır, router gezinmez. |
text |
Bağlantının çocuğu yoksa metni; çocuk varsa çocuklar kullanılır. |
bypass |
true ise tıklama router'a gitmez; bağlantı tarayıcıda normal bir bağlantı gibi açılır. |
Ctrl/Cmd/Shift/Alt ile yapılan tıklama tarayıcıya bırakılır. Diğer tıklamalarda RouterLink router.navigate(to) çağırır ve mevcut URL ile eşleşmeye göre sınıfları uygular:
| Sınıf / geri çağırım | Ne zaman |
|---|---|
activeClass, onActive / offActive |
Mevcut yol to ile başlıyorsa (segment bazında; tam eşleşme dahil). /notes/5'teyken to="/notes" aktiftir. |
exactClass, onExact / offExact |
Yalnızca mevcut yol to ile tam eşleştiğinde (sorgu dizesi ve # yok sayılır). |
Tam eşleşmede iki sınıf birlikte uygulanır. to="/" yalnızca kök yolda aktif olur; her yolun öneki sayılmaz.
Herhangi bir bileşende rota sınıfları — enableRouterClassing
RouterLink'in sınıf mantığı her bileşene açıktır: motif.options.enableRouterClassing'e bir RouterClassingSettings yazıldığında bileşenin elemanı, geçerli adres path ile eşleştikçe sınıf alır. Menü öğesi, sekme ya da kenar çubuğu başlığı gibi <a> olmayan elemanlar için kullanılır. NavItem bir <li>'dir, metnini çocuk olarak alır:
import { Component } from "@motifx/core";
export class NavItem extends Component<HTMLLIElement, { path: string }> {
override onConfigured() {
this.motif.options.enableRouterClassing = {
to: "all",
path: this.props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
}
override view() {
return <span>{this.childs}</span>;
}
}
import type { ComponentBase } from "@motifx/core";
export function NavItem(props: { path: string; childs?: ComponentBase[] }) {
return (
<li onConfigured={(item) => {
item.motif.options.enableRouterClassing = {
to: "all",
path: props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
}}>
<span>{props.childs}</span>
</li>
);
}
import { motifOptions } from "@motifx/core";
export const NavItem = (props: { path: string }) => motifOptions({
el: "li",
onConfigured() {
this.motif.options.enableRouterClassing = {
to: "all",
path: props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
},
view() {
return <span>{this.childs}</span>;
},
});
import { Component, ComponentBase, motifComponent } from "@motifx/core";
export class NavItem extends Component<HTMLLIElement, { path: string }> {
static override elementTag = "li";
override onConfigured() {
this.motif.options.enableRouterClassing = {
to: "all",
path: this.props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
}
override view() {
return motifComponent("span", (span: ComponentBase) => span.controls.add(...(this.childs ?? [])));
}
}
import { ComponentBase, motifComponent } from "@motifx/core";
export function NavItem(props: { path: string; childs?: ComponentBase[] }) {
return motifComponent("li", {
onConfigured: (item: ComponentBase) => {
item.motif.options.enableRouterClassing = {
to: "all",
path: props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
},
initializeComponent: (item: ComponentBase) => item.controls.add(motifComponent("span", (span: ComponentBase) => span.controls.add(...(props.childs ?? [])))),
});
}
import { ComponentBase, motifComponent, motifOptions } from "@motifx/core";
export const NavItem = (props: { path: string }) => motifOptions({
el: "li",
onConfigured() {
this.motif.options.enableRouterClassing = {
to: "all",
path: props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
},
view() {
return motifComponent("span", (span: ComponentBase) => span.controls.add(...(this.childs ?? [])));
},
});
import { Component } from "@motifx/core";
export class NavItem extends Component {
static elementTag = "li";
onConfigured() {
this.motif.options.enableRouterClassing = {
to: "all",
path: this.props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
}
view() {
return <span>{this.childs}</span>;
}
}
export function NavItem(props) {
return (
<li onConfigured={(item) => {
item.motif.options.enableRouterClassing = {
to: "all",
path: props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
}}>
<span>{props.childs}</span>
</li>
);
}
import { motifOptions } from "@motifx/core";
export const NavItem = (props) => motifOptions({
el: "li",
onConfigured() {
this.motif.options.enableRouterClassing = {
to: "all",
path: props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
},
view() {
return <span>{this.childs}</span>;
},
});
import { Component, motifComponent } from "@motifx/core";
export class NavItem extends Component {
static elementTag = "li";
onConfigured() {
this.motif.options.enableRouterClassing = {
to: "all",
path: this.props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
}
view() {
return motifComponent("span", (span) => span.controls.add(...(this.childs ?? [])));
}
}
import { motifComponent } from "@motifx/core";
export function NavItem(props) {
return motifComponent("li", {
onConfigured: (item) => {
item.motif.options.enableRouterClassing = {
to: "all",
path: props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
},
initializeComponent: (item) => item.controls.add(motifComponent("span", (span) => span.controls.add(...(props.childs ?? [])))),
});
}
import { motifComponent, motifOptions } from "@motifx/core";
export const NavItem = (props) => motifOptions({
el: "li",
onConfigured() {
this.motif.options.enableRouterClassing = {
to: "all",
path: props.path,
activeClass: "is-active",
exactClass: "is-exact",
};
},
view() {
return motifComponent("span", (span) => span.controls.add(...(this.childs ?? [])));
},
});
Kullanımı; /notes adresinde ilk öğe is-active is-exact, /notes/5'te yalnız is-active alır:
<ul class="menu">
<NavItem path="/notes">Tüm notlar</NavItem>
<NavItem path="/archive">Arşiv</NavItem>
</ul>
const menu = motifComponent("ul", (ul: ComponentBase) => {
ul.class.add("menu");
ul.controls.add(
motifComponent(NavItem, { path: "/notes", childs: [motifComponent("text", (node: ComponentBase) => node.setText("Tüm notlar"))] }),
motifComponent(NavItem, { path: "/archive", childs: [motifComponent("text", (node: ComponentBase) => node.setText("Arşiv"))] }),
);
});
<ul class="menu">
<NavItem path="/notes">Tüm notlar</NavItem>
<NavItem path="/archive">Arşiv</NavItem>
</ul>
const menu = motifComponent("ul", (ul) => {
ul.class.add("menu");
ul.controls.add(
motifComponent(NavItem, { path: "/notes", childs: [motifComponent("text", (node) => node.setText("Tüm notlar"))] }),
motifComponent(NavItem, { path: "/archive", childs: [motifComponent("text", (node) => node.setText("Arşiv"))] }),
);
});
| Alan | Açıklama |
|---|---|
path |
Karşılaştırılacak yol. |
to |
Hangi eşleşmelerin işleneceği: 'all' (ikisi), 'active', 'exact', 'none'. |
activeClass / exactClass |
Boşlukla ayrılmış sınıf adları; eşleşme durumuna göre classList.toggle edilir. |
onActive / offActive / onExact / offExact |
Her değerlendirmede eşleşme durumuna göre çağrılan geri çağrılar. |
Eşleşme kuralları RouterLink ile aynıdır (aktif = segment öneki ya da tam; exact = tam; sorgu ve # yok sayılır). Ayar yazıldığı anda bir kez değerlendirilir, sonra her gezinmede (onRouterChanged) yeniden; abonelik bileşenle birlikte kalkar. Değerlendirme hatası MJX105 olarak raporlanır. Router kurulmamışsa (useRouter yok) hiçbir şey yapmaz. Bileşenin bir elemanı olmalıdır; elemansız (fragment) bileşende sınıf yazılacak eleman yoktur (bkz. Kök eleman).
Sonraki adım
Koddan gezinmek ve rota durumunu okumak için Gezinme ve Rota Durumu bölümüne geçin.