JavaScript Tips | 文字列ユーティリティ:業務用 - パンくず生成

JavaScript JavaScript
スポンサーリンク

何をしたいユーティリティか:「パンくず生成」

ここでの「パンくず生成」は、
「今いるページまでの階層(ホーム > マスタ > ユーザー一覧 > ユーザー詳細)」を、決まったルールで文字列や配列として作る」ユーティリティです。

画面の上に出ている、あの「階層ナビゲーション」です。
業務システムでは、画面数が増えるほど「自分がどこにいるか」が分かりにくくなるので、
パンくずをきちんと設計しておくと、使い勝手が一気に良くなります。


パンくずに必要な情報を整理する

1 要素に持たせたい情報

パンくずの 1 つ 1 つは、だいたい次の 2 つを持っています。

  • 表示名(例: "ホーム", "マスタ", "ユーザー一覧"
  • リンク先 URL(例: "/", "/masters", "/masters/users"

一番右の「現在ページ」はリンクなしにすることが多いですが、
データ構造としては「全部リンク付き」で持っておき、
表示側で「最後だけリンクを外す」という実装にするのが扱いやすいです。


パンくずの「型」を決める

型イメージ

JavaScript では、パンくずはこんな配列で表現できます。

const breadcrumbs = [
  { label: "ホーム", path: "/" },
  { label: "マスタ", path: "/masters" },
  { label: "ユーザー一覧", path: "/masters/users" },
  { label: "ユーザー詳細", path: "/masters/users/123" },
];
JavaScript

この「配列の形」をユーティリティの出力として固定してしまえば、
あとはフレームワーク側(React / Vue など)で自由に描画できます。


一番シンプルな「手動指定」パンくず生成

配列をそのまま返す関数

まずは、「呼び出し側で配列を組んで、それを返すだけ」の超シンプル版です。

function buildBreadcrumb(items) {
  if (!Array.isArray(items)) {
    return [];
  }

  return items.map((item) => ({
    label: String(item.label ?? ""),
    path: item.path ?? null,
  }));
}
JavaScript

重要なポイント

items が配列でなければ空配列を返すようにして、
呼び出し側のミスで落ちないようにしています。

label は必ず文字列に変換し、
pathnull を許容しています(リンクなしの要素も表現できるように)。

この関数自体は単純ですが、
「パンくずはこの形で扱う」というルールをコードで固定する役割があります。


ルート定義からパンくずを組み立てる

ルート情報を「マスタ」として持つ

業務システムでは、URL と画面名の対応をどこかにまとめておくと便利です。
例えば、こんな「ルート定義」を用意します。

const ROUTES = {
  home: { label: "ホーム", path: "/" },
  masters: { label: "マスタ", path: "/masters" },
  users: { label: "ユーザー一覧", path: "/masters/users" },
  userDetail: { label: "ユーザー詳細", path: "/masters/users/:id" },
};
JavaScript

ここで大事なのは、「キー(home, masters など)」でルートを識別していることです。
URL が変わっても、このマスタだけ直せば済むようにしておきます。

ルートキーの配列からパンくずを作る

例えば、「ユーザー詳細」画面のパンくずは、

  • home
  • masters
  • users
  • userDetail

という順番のルートキーで表せます。

これをユーティリティに渡して、パンくず配列を作ります。

function buildBreadcrumbFromRouteKeys(routeKeys, params = {}) {
  if (!Array.isArray(routeKeys)) {
    return [];
  }

  const items = [];

  for (const key of routeKeys) {
    const route = ROUTES[key];
    if (!route) continue;

    const label = route.label;
    const path = route.path ? fillPathParams(route.path, params) : null;

    items.push({ label, path });
  }

  return items;
}
JavaScript

ここで fillPathParams は、"/masters/users/:id":id を実際の値で置き換える小さな関数です。


パスパラメータを埋める小さな関数

:id などを実際の値に置き換える

function fillPathParams(path, params) {
  if (!path || !params) return path;

  return path.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
    const value = params[key];
    return value != null ? encodeURIComponent(String(value)) : "";
  });
}
JavaScript

重要なポイント

/:id のような部分を正規表現で見つけて、
params.id の値で置き換えています。

encodeURIComponent を通しているので、
ID に記号が入っていても URL として安全な形になります。


実際の動きを例で確認する

ユーザー詳細画面のパンくず

const routeKeys = ["home", "masters", "users", "userDetail"];
const params = { id: 123 };

const breadcrumbs = buildBreadcrumbFromRouteKeys(routeKeys, params);
JavaScript

breadcrumbs の中身はこうなります。

[
  { label: "ホーム", path: "/" },
  { label: "マスタ", path: "/masters" },
  { label: "ユーザー一覧", path: "/masters/users" },
  { label: "ユーザー詳細", path: "/masters/users/123" },
]
JavaScript

あとは、フロント側で

  • 最後の要素だけリンクなしで表示
  • それ以外は <a href="..."> で表示

というルールで描画すれば、きれいなパンくずになります。


パンくず文字列として組み立てるユーティリティ

「表示用文字列」だけ欲しい場合

ログやタイトルなどで、「パンくずを 1 本の文字列として使いたい」こともあります。
その場合は、配列から文字列を作る関数を用意します。

function breadcrumbToString(breadcrumbs, separator = " > ") {
  if (!Array.isArray(breadcrumbs)) {
    return "";
  }

  const labels = breadcrumbs.map((b) => b.label).filter((x) => x);
  return labels.join(separator);
}
JavaScript

実際の動き

const text = breadcrumbToString(breadcrumbs);
// "ホーム > マスタ > ユーザー一覧 > ユーザー詳細"
JavaScript

これをそのままログに出したり、
HTML タイトルに混ぜたりすることもできます。


実務で意識してほしい設計のポイント

「パンくずはルート定義から作る」を徹底する

画面ごとに、

const breadcrumbs = [
  { label: "ホーム", path: "/" },
  { label: "マスタ", path: "/masters" },
  ...
];
JavaScript

とベタ書きし始めると、
画面名や URL を変更したときに、全画面を探して直すことになります。

ルート定義(ROUTES)を 1 箇所にまとめ、
パンくずは「ルートキーの配列」から作る、という形にしておくと、
仕様変更に強くなります。

「どこまでをパンくずに出すか」を決める

業務システムでは、階層が深くなりすぎると、
パンくずが長くなりすぎて逆に見づらくなることがあります。

例えば、

  • ホーム
  • 受注管理
  • 受注一覧
  • 受注詳細
  • 明細編集

まで全部出すのか、
「受注一覧」までにしておくのか、
「受注詳細」までにしておくのか。

この「深さのルール」も、
ルート定義やルートキーの配列でコントロールできるようにしておくと、
あとから調整しやすくなります。

パラメータをタイトルに含めるかどうか

"ユーザー詳細 #123" のように、
ID をパンくずに含めるかどうかも設計ポイントです。

含める場合は、ROUTES.userDetail.label を固定文字列ではなく、
関数にしてしまう方法もあります。

const ROUTES = {
  userDetail: {
    label: (params) => `ユーザー詳細 #${params.id}`,
    path: "/masters/users/:id",
  },
};
JavaScript

そして、buildBreadcrumbFromRouteKeys 側で、

const label = typeof route.label === "function"
  ? route.label(params)
  : route.label;
JavaScript

のように呼び分ければ、
「ID 付きのラベル」をパンくずに出せます。


少し手を動かして感覚をつかむ

コンソールで、次のようなコードを実際に打ってみてください。

const routeKeys = ["home", "masters", "users", "userDetail"];
const params = { id: 123 };

const breadcrumbs = buildBreadcrumbFromRouteKeys(routeKeys, params);
breadcrumbs;

breadcrumbToString(breadcrumbs);
JavaScript

配列の中身と、文字列の結果を見て、

  • ラベルとパスが期待通りか
  • パスパラメータが正しく埋まっているか
  • 文字列のパンくずが自然か

を確認してみてください。

そのうえで、自分のプロジェクトに

export const ROUTES = { ... };
export function buildBreadcrumbFromRouteKeys(...) { ... }
export function breadcrumbToString(...) { ... }
JavaScript

のような形で置き、

「パンくずが欲しくなったら、必ずこの“パンくず生成ユーティリティ”を通す」

というルールを作ってみてください。
それだけで、あなたのシステムのパンくずは、場当たり的な配列ベタ書きから、
意図と一貫性を備えた「業務レベルのナビゲーション設計」に変わっていきます。

タイトルとURLをコピーしました