Навигационные хуки
Навигационный хук (guard, «охранник») — функция, которую роутер вызывает перед каждым переходом. Она может пропустить переход, отменить его или перенаправить на другую страницу. Так закрывают раздел управления блогом от тех, кто не вошёл.
Признак входа
Для примера хватит простого композабла с общим состоянием. Создайте src/composables/useAuth.js:
// src/composables/useAuth.js
import { ref } from 'vue'
const isLoggedIn = ref(false)
export function useAuth() {
function login() {
isLoggedIn.value = true
}
function logout() {
isLoggedIn.value = false
}
return { isLoggedIn, login, logout }
}ref объявлен вне функции, поэтому все компоненты и роутер видят одно и то же значение. В настоящем приложении здесь был бы запрос к серверу.
Пометка маршрутов
В поле meta маршрута можно положить любые свои данные. Отметьте раздел /admin и добавьте страницу входа в src/router/index.js:
// src/router/index.js, фрагмент массива routes
const routes = [
{
path: '/admin',
component: () => import('../views/AdminLayout.vue'),
meta: { requiresAuth: true },
children: [
{ path: '', name: 'admin-posts', component: () => import('../views/AdminPostsView.vue') },
],
},
{ path: '/login', name: 'login', component: () => import('../views/LoginView.vue') },
]meta дочерних маршрутов наследует пометку родителя, поэтому /admin/new тоже будет закрыт.
Хук beforeEach
После создания роутера, перед export default router, добавьте проверку:
// src/router/index.js
import { useAuth } from '../composables/useAuth.js'
router.beforeEach((to) => {
const { isLoggedIn } = useAuth()
if (to.meta.requiresAuth && !isLoggedIn.value) {
return { name: 'login', query: { redirect: to.fullPath } }
}
})to — маршрут, куда идёт переход. Если функция возвращает адрес, роутер перенаправит туда; если ничего не возвращает — пропустит переход.
| Возвращаемое значение | Результат |
|---|---|
Ничего или true | Переход разрешён |
false | Переход отменён, пользователь остаётся на месте |
| Адрес или объект маршрута | Перенаправление |
Страница входа
<!-- src/views/LoginView.vue -->
<script setup>
import { useRoute, useRouter } from 'vue-router'
import { useAuth } from '../composables/useAuth.js'
const route = useRoute()
const router = useRouter()
const { login } = useAuth()
function enter() {
login()
router.push(route.query.redirect || '/')
}
</script>
<template>
<h1>Вход</h1>
<button @click="enter">Войти как Анна</button>
</template>Откройте http://localhost:5173/admin — адрес сменится на /login?redirect=/admin. После нажатия «Войти как Анна» откроется раздел управления.
Хук на одном маршруте
Проверку, нужную только одному маршруту, пишут прямо в нём в поле beforeEnter. Например, пускать на страницу статьи только с числовым номером:
// src/router/index.js, маршрут статьи
const postRoute = {
path: '/posts/:id',
name: 'post',
component: () => import('../views/PostView.vue'),
beforeEnter: (to) => {
if (!/^\d+$/.test(to.params.id)) {
return { name: 'home' }
}
},
}Адрес /posts/abc перенаправит на главную, а /posts/5 откроет статью.
Частая ошибка
Перенаправить на страницу входа без проверки, куда идёт переход: return { name: 'login' } для всех маршрутов. Переход на /login тоже проходит через beforeEach, снова перенаправляется на /login, и роутер выводит ошибку о бесконечном перенаправлении. Перенаправляйте только при выполнении условия, как с to.meta.requiresAuth выше.