05 β Vue Router¶
β¬ οΈ Oldingi: 04 β Composition API Β· π README Β· Keyingi: 06 β Pinia β‘οΈ
SPA (Single Page Application)'da sahifa qayta yuklanmaydi β URL o'zgaradi, JS kerakli komponentni almashtiradi. Vue Router shuni boshqaradi.
Laravel analogiyasi: routes/web.php β URL'ni controller'ga bog'laysan. Vue Router β URL'ni komponentga bog'laydi. Route guard'lar β Laravel middleware (auth, can) ning frontend ekvivalenti.
Eslatma: Nuxt'da Vue Router'ni qo'lda sozlamaysan β fayl tuzilishi avtomatik route yasaydi (07-modul). Lekin ostidagi mexanizm shu Vue Router. Buni bilish β Nuxt'ni tushunish uchun shart.
5.1 O'rnatish va asosiy setup¶
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
const routes = [
{ path: '/', name: 'home', component: Home },
{ path: '/about', name: 'about', component: About },
]
export const router = createRouter({
history: createWebHistory(), // toza URL (/about). createWebHashHistory() β /#/about
routes,
})
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router'
createApp(App).use(router).mount('#app')
<!-- App.vue -->
<template>
<nav>
<RouterLink to="/">Bosh sahifa</RouterLink>
<RouterLink :to="{ name: 'about' }">Biz haqimizda</RouterLink>
</nav>
<RouterView /> <!-- bu yerda joriy route komponenti render bo'ladi -->
</template>
<RouterLink>β<a>o'rniga (sahifa qayta yuklanmaydi). Faol linkga avtomatik.router-link-activeklassi qo'shiladi.<RouterView>β joriy route'ga mos komponent shu yerda chiqadi (Laravel@yield('content')kabi).toβ string (/about) yoki obyekt ({ name: 'about' }). Nomli route afzal β URL o'zgarsa, link buzilmaydi.
Umumiy mexanizm quyidagicha: URL routes jadvaliga solishtiriladi, mos komponent <RouterView> ichida render bo'ladi, sahifaning qolgan qismi o'zgarmaydi:
5.2 Dynamic routes (parametrlar)¶
const routes = [
{ path: '/users/:id', name: 'user', component: UserDetail },
{ path: '/posts/:category/:slug', component: Post },
{ path: '/files/:path(.*)', component: File }, // wildcard (qolgan hammasi)
]
<!-- UserDetail.vue -->
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params.id) // URL'dagi :id
console.log(route.query.tab) // ?tab=info
console.log(route.path) // /users/5
</script>
<template>
<h1>User #{{ route.params.id }}</h1>
</template>
MUHIM β param o'zgarganda komponent qayta yaratilmaydi:
/users/1 β /users/2 ga o'tilganda Vue komponentni qayta ishlatadi (qayta create qilmaydi), shuning uchun onMounted qaytadan ishlamaydi. Param o'zgarishini kuzatish kerak:
import { watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
watch(() => route.params.id, (newId) => {
fetchUser(newId) // har param o'zgarganda qayta yukla
}, { immediate: true })
Bu β eng ko'p uchraydigan router bug'i. Yodda tut.
5.3 Dasturiy navigatsiya (programmatic)¶
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
function goToProfile(id) {
router.push({ name: 'user', params: { id } })
}
router.push('/about') // string
router.push({ path: '/users/5', query: { tab: 'posts' } })
router.replace('/login') // tarixga qo'shmaydi (back ishlamaydi)
router.back() // brauzer "orqaga"
router.go(-2)
</script>
useRoute()(joriy route ma'lumoti, o'qish) vauseRouter()(navigatsiya, harakat) β ikkisini chalkashtirma. Route = ma'lumot, Router = boshqaruv.
5.4 Nested routes (ichma-ich)¶
Layout ichida o'zgaruvchi qism (masalan, dashboard'da yon menyu doim qoladi, o'ng tomon o'zgaradi):
const routes = [
{
path: '/dashboard',
component: DashboardLayout,
children: [
{ path: '', name: 'dash-home', component: DashHome }, // /dashboard
{ path: 'profile', component: Profile }, // /dashboard/profile
{ path: 'settings', component: Settings }, // /dashboard/settings
],
},
]
<!-- DashboardLayout.vue -->
<template>
<aside>Yon menyu (doim qoladi)</aside>
<main>
<RouterView /> <!-- bola route shu yerda -->
</main>
</template>
Har nest darajasiga bittadan <RouterView>. Ota komponent qoladi, ichidagi <RouterView> bola route bilan almashadi.
Buni vizual ko'rinishda quyidagicha tasavvur qil:
5.5 Lazy loading (route-level code splitting)¶
Har komponentni boshidan yuklash o'rniga β kerak bo'lganda yuklash. Bundle hajmi kichrayadi, ilk yuklanish tezlashadi:
const routes = [
{ path: '/', component: Home }, // bu darrov kerak β eager
{
path: '/admin',
component: () => import('@/views/Admin.vue'), // lazy β alohida chunk
},
]
() => import(...) β Vite alohida .js chunk yasaydi, faqat /admin ga kirilganda yuklanadi. Katta ilovalarda doim og'ir/kam ishlatiladigan sahifalarni lazy qil.
5.6 Navigation guards β middleware ekvivalenti¶
Navigatsiyani to'xtatish/yo'naltirish (auth tekshirish, ruxsat, "saqlanmagan o'zgarishlar" ogohlantirishi):
Global guard (beforeEach)¶
// router/index.js
router.beforeEach((to, from) => {
const isAuth = !!localStorage.getItem('token')
if (to.meta.requiresAuth && !isAuth) {
return { name: 'login', query: { redirect: to.fullPath } } // yo'naltir
}
// return true yoki hech narsa β davom et
})
Route'ga meta qo'shasan:
Per-route guard (beforeEnter)¶
{
path: '/admin',
component: Admin,
beforeEnter: (to, from) => {
if (!isAdmin()) return { name: 'home' }
},
}
In-component guard (onBeforeRouteLeave)¶
import { onBeforeRouteLeave } from 'vue-router'
onBeforeRouteLeave((to, from) => {
if (hasUnsavedChanges.value) {
return window.confirm('Saqlanmagan o\'zgarishlar bor. Chiqasizmi?')
}
})
Guard'lar ketma-ketligi (soddalashtirilgan): beforeEach (global) β beforeEnter (route) β komponent ichidagi guard'lar β navigatsiya yakunlanadi.
Quyidagi diagramma bu oqimni ko'rsatadi β har bosqich "davom et yoki to'xtat/yo'naltir" deb qaror qiladi:
Bu Laravel middleware pipeline'iga juda o'xshaydi: har bosqich "davom et yoki to'xtat/yo'naltir" deb qaror qiladi.
5.7 Foydali narsalar¶
// Scroll xulqi (yangi sahifada tepaga)
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) return savedPosition // back/forward'da eski joyga
if (to.hash) return { el: to.hash } // #section ga
return { top: 0 }
},
})
// 404
{ path: '/:pathMatch(.*)*', name: 'not-found', component: NotFound }
// Redirect & alias
{ path: '/home', redirect: '/' }
{ path: '/', component: Home, alias: '/bosh' }
// Props orqali param uzatish (route'ga bog'liqlikni kamaytiradi)
{ path: '/users/:id', component: UserDetail, props: true }
// UserDetail endi route'ni emas, oddiy `id` prop'ini qabul qiladi
<RouterView> da transition + KeepAlive:
<RouterView v-slot="{ Component }">
<Transition name="fade" mode="out-in">
<KeepAlive>
<component :is="Component" />
</KeepAlive>
</Transition>
</RouterView>
Xulosa¶
createRouter+createWebHistory,<RouterLink>+<RouterView>- Dynamic param:
:idβroute.params.id; param o'zgarsa watch qil (komponent qayta yaratilmaydi) useRoute()= o'qish,useRouter()= harakat (push/replace/back)- Nested routes β layout + bola
<RouterView> - Lazy loading β
() => import(...), bundle splitting - Guards = middleware: global
beforeEach, routebeforeEnter, komponentonBeforeRouteLeave;metabilan auth/role - Nomli route +
props: trueβ toza, barqaror
π― Masalalar (kamida 20 ta)¶
Asosiy (1β7)¶
- 3 sahifali sayt: Home, About, Contact. Nav +
<RouterView>.<RouterLink>bilan o'tib ko'r, sahifa qayta yuklanmasligini tasdiqla. - Faol linkni
.router-link-activeorqali boshqacha rangga bo'ya. - Nomli route'lar (
name) qo'shib,:to="{ name: '...' }"bilan navigatsiya qil. router.pushbilan dasturiy o'tish: tugma bosilganda/aboutga o't.- 404 sahifa qo'sh (
/:pathMatch(.*)*); mavjud bo'lmagan URL'ga kirib sina. /homeβ/redirect qo'sh.scrollBehaviorbilan har yangi sahifada tepaga scroll qil.
Dynamic & data (8β13)¶
/users/:idroute; sahifadaroute.params.idni ko'rsat.- Param watch (β
): Foydalanuvchilar ro'yxatidan
/users/1,/users/2ga o'tganda sahifa ma'lumoti yangilansin (watch(() => route.params.id, ..., {immediate:true})). - Query string (β
):
/search?q=vueβroute.query.qni ko'rsat; inputga yozsang URL query'nirouter.pushbilan yangila. props: true(β ):UserDetailni route'ga bog'lamasdan,idni prop sifatida qabul qildir.- Master-detail (β
β
):
/productsro'yxat β element bosilsa/products/:iddetail sahifa; "Orqaga" tugmasirouter.back(). - Pagination URL'da (β
β
):
/posts?page=2β sahifa raqami query'da saqlansin, refresh'da ham qolsin.
Nested & lazy (14β17)¶
- Dashboard layout (β
β
):
/dashboardlayout +children:''(home),profile,settings. Yon menyu doim qolsin, o'ng tomon almashsin. - Ikki darajali nested (β
β
):
/dashboard/usersichida yana/dashboard/users/:idnest qil. - Lazy loading (β
):
Adminsahifasini() => import()bilan yukla; Network tab'da alohida chunk yuklanishini ko'rsat. - Transition (β
β
):
<RouterView v-slot>bilan sahifalar orasiga fade animatsiya qo'sh.
Guards (18β23)¶
- Auth guard (β
β
):
meta.requiresAuthbo'lgan/dashboardni himoyala; token yo'q bo'lsa/loginga yo'naltir (beforeEach). - Redirect after login (β
β
): Login'da
query.redirectni ishlatib, foydalanuvchini kelgan sahifasiga qaytar. - Role guard (β
β
):
meta.role: 'admin'β admin bo'lmasa/403ga. - Leave guard (β
β
): Forma sahifasida o'zgarish bo'lsa,
onBeforeRouteLeavebilan "Saqlanmagan o'zgarishlar bor" deb ogohlantir. - Title (β
):
beforeEachdato.meta.titlenidocument.titlega yoz. - EduCore router skeleti (β
β
β
):
/login(public),/app(auth layout + children: dashboard, students, payments),/admin(role: admin). Guard'larnimeta+beforeEachbilan to'liq qur. (Bu Nuxt'da fayl-tuzilish bilan ko'rinishini 07-modulda solishtirasan.)
β Tanlangan yechimlar¶
9 β Param watch bilan data yangilash
<!-- UserDetail.vue -->
<script setup>
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const user = ref(null)
async function load(id) {
// soxta "API"
user.value = { id, name: `User ${id}` }
}
watch(() => route.params.id, (id) => load(id), { immediate: true })
</script>
<template>
<h1 v-if="user">{{ user.name }} (#{{ user.id }})</h1>
</template>
18 β Auth guard + redirect
// router/index.js
router.beforeEach((to) => {
const isAuth = !!localStorage.getItem('token')
if (to.meta.requiresAuth && !isAuth) {
return { name: 'login', query: { redirect: to.fullPath } }
}
})
β‘οΈ Keyingi: 06 β Pinia