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.

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.