跳到正文
FunCoding

vue-breadcrumb

Give a Vue SPA route its breadcrumb, entirely from the router file. The breadcrumb component reads four declarations in `meta` — `showBreadcrumb`, `breadcrumb`, `breadcrumbParents` and `breadcrumbResource` — and knows no page by name. Auto-invoke when: the user adds a route to any file in `assets/vue/router/`, creates a new Vue page or view that needs a URL, migrates a legacy PHP page to Vue, reports a wrong or missing breadcrumb, sees the console warning "[Breadcrumb] Route ... has no meta.breadcrumb", or mentions breadcrumb, crumb, trail, `meta.breadcrumb`, `breadcrumbParents` or `breadcrumbResource`. Do NOT invoke for: the legacy PHP breadcrumb (`window.breadcrumb`, injected by `public/main/`), for `/admin/settings/<namespace>` (its last crumb is read from the DOM), or for styling work on `Breadcrumb.vue` itself.

Star
1,011
许可证
GPL-3.0
最近提交
2026年10月13日

.claude/skills/vue-breadcrumb/SKILL.md

在 GitHub 上查看

Never edit assets/vue/components/Breadcrumb.vue to give a page its trail. The component holds no page name and no path. Everything a trail needs is declared in the route.

The three steps that always apply

1. Ask for a breadcrumb

Set showBreadcrumb: true in the meta of the parent route. Without it, App.vue does not mount the component and nothing you declare below has any effect.

A route that only sometimes has a trail declares a function instead. It receives the route:

// The personal agenda hangs from no course, so it has nothing to show.
showBreadcrumb: (route) => Number(route.query?.cid || 0) > 0,

2. Declare the label

Set meta.breadcrumb on the parent and on every leaf. The value is a translation key, never translated text.

export default {
  path: "/resources/checklist/:node/",
  meta: {
    requiresAuth: true,
    showBreadcrumb: true,
    tool: "checklist",
    breadcrumb: "Checklists",
  },
  name: "checklist",
  component: () => import("../components/layout/SimpleRouterViewLayout.vue"),
  redirect: { name: "ChecklistList" },
  children: [
    { name: "ChecklistList", path: "", meta: { breadcrumb: "" }, component: ... },
    { name: "ChecklistCreate", path: "create", meta: { breadcrumb: "Create" }, component: ... },
    { name: "ChecklistUpdate", path: "edit/:id", meta: { breadcrumb: "Edit" }, component: ... },
  ],
}

breadcrumb: "" means omit this crumb, and it is what a list page usually wants: the tool crumb already names that page. An absent property is a different thing — it triggers the development warning and shows the raw route name.

The label can also be a function returning a key, when it depends on the request:

breadcrumb: (route) => {
  const gid = Number(route.query?.gid || 0)
  const cid = Number(route.query?.cid || 0)

  return gid > 0 ? "Group agenda" : cid > 0 ? "Agenda" : "Personal agenda"
},

A function may also return "" to omit the crumb, but only on a route that declares breadcrumbParents: the tool and resource branches still compare the raw meta.breadcrumb property, so there a function is never empty. Declare it when the page's own name exists for some requests only. AdminStatistics in assets/vue/router/admin.js is the reference — its key comes from activeReportLabelKey (assets/vue/utils/statisticsReports.js), which names the report in route.query.report and returns "" when there is none.

3. Register every key

A key that is new to the platform goes by hand into three files:

  • assets/locales/en_US.json
  • translations/messages.pot
  • translations/messages.en_US.po

php bin/console chamilo:update_vue_translations does not create keys. It only propagates to the other locales the keys that en_US.json already holds. Never commit a mass regeneration of assets/locales/*.json; a single new line is fine.

Check first whether the key exists — most tool names already do:

python3 -c "import json; d=json.load(open('assets/locales/en_US.json')); print('Checklists' in d)"

The two extra declarations

Give the leaf the fixed ancestors that always precede it. Each entry is { label, route }, where label is a translation key and route is a Vue Router location — prefer { name: ... } over a raw path.

meta: {
  breadcrumb: "Import checklists",
  breadcrumbParents: [
    { label: "Administration", route: { name: "AdminIndex" } },
    { label: "Checklists", route: { name: "ChecklistAdminList" } },
  ],
}

When several routes share the same ancestors, declare the lists once at the top of the file. assets/vue/router/admin.js is the reference, with adminCrumb, classesCrumbs, multiUrlCrumbs and accessUrlCrumbs; room.js and branch.js show the smaller shape.

A route with breadcrumbParents owns its whole trail and takes the first branch of buildBreadcrumb, so nothing else runs for it.

The ancestors are fixed, but the leaf's own crumb is not: an empty key drops it and leaves the ancestors standing. That is how a page hangs a report or filter name off a parent that links back to its own bare URL, and it is the only branch where a function may return "".

Declare it on the parent, when the trail has to name the thing the user opened.

// One resource at a time: list -> resource -> sub-page.
breadcrumbResource: {
  trail: "self",
  listRoute: "AssignmentsList",
  detailRoute: "AssignmentDetail",
  detailParam: "id",
}

// A chain of folders, walked up the resource-node parents.
breadcrumbResource: {
  trail: "ancestors",
  listRoute: "DocumentsList",
  detailRoute: "DocumentsList",
}

This declaration also drives the fetch: loadResourceNodeIfNeeded loads the resource node only for a route whose tool declares it. Nothing else has to be wired.

Do not do these

  • Do not add a rule to Breadcrumb.vue. If a trail seems to need one, the shape is probably already covered by one of the four declarations. Read the component's own builders first. A rule that names a page or a route never belongs there. Widening a contract the declarations already document is a different thing, and rare: do it only when a builder fails to honour a declaration the skill already describes.
  • Do not match route names by substring. A rule like route.name.includes("Page") puts a "Pages" crumb on every wiki page of every course.
  • Do not pass translated text as a label. The component calls t() on what you declare.
  • Do not expect a one-crumb trail to appear. The component gives the first crumb to the PrimeVue home slot, and the container is hidden while the rest is empty. A page whose trail reduces to its tool shows nothing.

Verify

# Fails when a route renders a breadcrumb without declaring its label.
yarn check:breadcrumb-routes

npx eslint assets/vue/router/
yarn dev

Then open the page and read the browser console. [Breadcrumb] Route "X" has no meta.breadcrumb means a declaration is missing. The warning is stripped from the production bundle.

Cover it

tests/playwright/features/breadcrumb.feature holds the breadcrumb scenarios. Add yours there.

Assert on CSS selectors, never on crumb text: this platform runs in many languages and the test environment is not always English.

Then I should see the ".app-breadcrumb a[href='/admin/urls']" element

An a[href] proves both that the ancestor is there and that it points at the right place. Two traps that cost real time:

  • The last crumb is a <span>, not a link. Asserting a[href] on the current page's own crumb never matches. Assert on an ancestor.
  • A tool with breadcrumbResource paints late. It waits for the resource-node fetch, well past Playwright's 15 s default. Use I wait up to 45 seconds for the element ... to appear.

Playwright needs BASE_URL=http://localhost inside the container, and the generated spec under tests/playwright/.features-gen/ is tracked, so run bddgen and commit it too.

相似的 Skill

prototype

MAmattpocock/skills288k近 7 天新增 10,178 个 star

angular-developer

AFaffaan-m/ECC278k近 7 天新增 4,046 个 star

官方

firecrawl-build-scrape

FIfirecrawl/firecrawl191k近 7 天新增 2,010 个 star

精选

frontend-design

为界面确定视觉方向和字体,避免模板化的默认样式。

ANanthropics/skills181k近 7 天新增 1,119 个 star

精选

theme-factory

为幻灯片、文档和网页套用主题配色与字体,内置 10 套主题。

ANanthropics/skills181k近 7 天新增 1,119 个 star

精选

web-artifacts-builder

用 React、Tailwind 和 shadcn/ui 构建多组件页面。

ANanthropics/skills181k近 7 天新增 1,119 个 star