用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill vue-router命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | vue-router |
| description | Vue Router 4 開發規範:路由設計、Navigation Guard、動態載入、Meta 型別安全與權限控制。 Use when this capability is needed. |
| metadata | {"author":"CloudyWing"} |
當偵測到專案使用 Vue Router 4(含 vue-router 4.x 相依套件)或使用者要求撰寫路由邏輯時,請自動套用以下規範。
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
const routes: ReadonlyArray<RouteRecordRaw> = [
{
path: '/',
component: () => import('@/layouts/DefaultLayout.vue'),
children: [
{
path: '',
name: 'Home',
component: () => import('@/views/HomeView.vue'),
},
{
path: 'orders',
name: 'OrderList',
component: () => import('@/views/orders/OrderListView.vue'),
meta: { requiresAuth: true },
},
{
path: 'orders/:id',
name: 'OrderDetail',
component: () => import('@/views/orders/OrderDetailView.vue'),
meta: { requiresAuth: true },
props: true,
},
],
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/LoginView.vue'),
meta: { guestOnly: true },
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('@/views/NotFoundView.vue'),
},
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
})
export default router
| 項目 | 規則 | 範例 |
|---|---|---|
| Route name | PascalCase | OrderDetail, UserProfile |
| Path | kebab-case | /order-items, /user-profile |
| 參數 | camelCase | :orderId, :userId |
| View 檔名 | PascalCase + View 後綴 | OrderDetailView.vue |
<RouterView /> 渲染子路由內容。// ✅ 正確:動態 import
{
path: '/orders',
component: () => import('@/views/orders/OrderListView.vue')
}
// ❌ 錯誤:靜態 import(會全部打包進主 bundle)
import OrderListView from '@/views/orders/OrderListView.vue'
{
path: '/orders',
component: OrderListView
}
// router/index.ts
router.beforeEach(async (to, from) => {
const authStore = useAuthStore()
// 需要認證的路由
if (to.meta.requiresAuth && !authStore.isAuthenticated) {
return {
name: 'Login',
query: { redirect: to.fullPath },
}
}
// 僅限訪客(已登入不可進入)
if (to.meta.guestOnly && authStore.isAuthenticated) {
return { name: 'Home' }
}
})
{
path: '/admin',
component: () => import('@/views/admin/AdminView.vue'),
beforeEnter: (to, from) => {
const authStore = useAuthStore()
if (!authStore.hasRole('admin')) {
return { name: 'Forbidden' }
}
}
}
<script setup lang="ts">
import { onBeforeRouteLeave } from 'vue-router'
const hasUnsavedChanges = ref(false)
onBeforeRouteLeave((to, from) => {
if (hasUnsavedChanges.value) {
const answer = window.confirm('尚有未儲存的變更,確定離開?')
if (!answer) {
return false
}
}
})
</script>
useXxxStore()(而非模組頂層),確保 Pinia 已初始化。false 取消導航;回傳路由物件重導向;不回傳或回傳 true 允許通過。async/await。// router/types.ts
export {}
declare module 'vue-router' {
interface RouteMeta {
requiresAuth?: boolean
guestOnly?: boolean
roles?: ReadonlyArray<string>
title?: string
}
}
tsconfig.json 涵蓋。to.meta.requiresAuth 等存取具備型別檢查。// 路由參數自動映射為元件 Props
{
path: '/orders/:id',
component: () => import('@/views/orders/OrderDetailView.vue'),
props: true // :id 會傳為 props.id
}
{
path: '/orders/:id',
component: () => import('@/views/orders/OrderDetailView.vue'),
props: (route) => ({
id: Number(route.params.id) // 轉型
})
}
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
// ✅ 使用 name 導航(路徑變更時不需改程式碼)
router.push({ name: 'OrderDetail', params: { id: orderId } })
// ✅ 附帶 query
router.push({ name: 'OrderList', query: { status: 'pending' } })
// ✅ 替換歷史記錄(返回鍵不會回到前一頁)
router.replace({ name: 'Home' })
// ❌ 避免:硬編碼路徑
router.push(`/orders/${orderId}`)
name,避免硬編碼路徑。params,查詢條件使用 query。router.afterEach((to) => {
const title = to.meta.title
document.title = title ? `${title} | MyApp` : 'MyApp'
})
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition // 瀏覽器返回時恢復滾動位置
}
if (to.hash) {
return { el: to.hash } // 錨點定位
}
return { top: 0 } // 新頁面回到頂端
}
})
大型專案可將路由定義拆分為多個模組:
// router/modules/order.ts
import type { RouteRecordRaw } from 'vue-router'
export const orderRoutes: ReadonlyArray<RouteRecordRaw> = [
{
path: 'orders',
name: 'OrderList',
component: () => import('@/views/orders/OrderListView.vue'),
meta: { requiresAuth: true, title: '訂單列表' },
},
{
path: 'orders/:id',
name: 'OrderDetail',
component: () => import('@/views/orders/OrderDetailView.vue'),
meta: { requiresAuth: true, title: '訂單明細' },
props: true,
},
]
// router/index.ts
import { orderRoutes } from './modules/order'
import { customerRoutes } from './modules/customer'
const routes: ReadonlyArray<RouteRecordRaw> = [
{
path: '/',
: (),
: [
...orderRoutes,
...customerRoutes,
],
},
]
Source: CloudyWing/ai-dotfiles — distributed by TomeVault.