Routing Composition API (useRouter/useRoute)
Composition API for Routing (useRouter/useRoute)
Vue Router 4.x provides two Composition APIs: useRouter
and useRoute
, which make it easier to access the router instance and current route information within the setup
function. These APIs replace the this.$router
and this.$route
from previous versions and are more suitable for use with the Composition API.
Basic Usage of useRouter
useRouter
returns the router instance, equivalent to the previous this.$router
. It allows us to perform programmatic navigation:
import { useRouter } from 'vue-router'
export default {
setup() {
const router = useRouter()
const navigateToHome = () => {
router.push('/home')
}
const replaceToAbout = () => {
router.replace('/about')
}
const goBack = () => {
router.go(-1)
}
return {
navigateToHome,
replaceToAbout,
goBack
}
}
}
Basic Usage of useRoute
useRoute
returns the current route object, equivalent to the previous this.$route
. It contains various information about the current route:
import { useRoute } from 'vue-router'
export default {
setup() {
const route = useRoute()
// Access route parameters
const userId = computed(() => route.params.id)
// Access query parameters
const searchQuery = computed(() => route.query.q)
// Access hash
const sectionHash = computed(() => route.hash)
return {
userId,
searchQuery,
sectionHash
}
}
}
Comparison Between Composition API and Options API
In the Options API, we typically access the router like this:
export default {
methods: {
navigate() {
this.$router.push('/somewhere')
}
},
computed: {
currentPath() {
return this.$route.path
}
}
}
In the Composition API, the code is clearer and more flexible:
import { useRouter, useRoute } from 'vue-router'
import { computed } from 'vue'
export default {
setup() {
const router = useRouter()
const route = useRoute()
const currentPath = computed(() => route.path)
const navigate = () => {
router.push('/somewhere')
}
return {
currentPath,
navigate
}
}
}
Using Router Outside of setup
Sometimes we need to access the router outside the setup
function, such as in utility functions:
// utils/navigation.js
import { useRouter } from 'vue-router'
export function useNavigation() {
const router = useRouter()
const navigateTo = (path) => {
router.push(path)
}
return {
navigateTo
}
}
Then use it in a component:
import { useNavigation } from '@/utils/navigation'
export default {
setup() {
const { navigateTo } = useNavigation()
const goToAbout = () => {
navigateTo('/about')
}
return {
goToAbout
}
}
}
Composition-Style Route Guards
Vue Router 4.x also provides Composition API-style navigation guards:
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
export default {
setup() {
onBeforeRouteLeave((to, from) => {
const answer = window.confirm('Are you sure you want to leave?')
if (!answer) return false
})
onBeforeRouteUpdate(async (to, from) => {
// Fetch new data when route parameters change
await fetchData(to.params.id)
})
}
}
Dynamic Route Matching
Using useRoute
, dynamic route parameters can be easily handled:
import { useRoute } from 'vue-router'
import { watch } from 'vue'
export default {
setup() {
const route = useRoute()
// Perform actions when route parameters change
watch(
() => route.params.id,
(newId) => {
fetchUserData(newId)
}
)
}
}
Accessing Route Meta Information
The meta
field in route configuration can be accessed via useRoute
:
import { useRoute } from 'vue-router'
import { computed } from 'vue'
export default {
setup() {
const route = useRoute()
const requiresAuth = computed(() => route.meta.requiresAuth)
const pageTitle = computed(() => route.meta.title || 'Default Title')
return {
requiresAuth,
pageTitle
}
}
}
Handling Nested Routes
When dealing with nested routes, useRoute
provides complete matched route records:
import { useRoute } from 'vue-router'
export default {
setup() {
const route = useRoute()
// Get all matched route records
const matchedRoutes = route.matched
// Find specific meta fields
const hasAdminAccess = matchedRoutes.some(
record => record.meta.requiresAdmin
)
}
}
Integration with Pinia State Management
Using router Composition APIs in Pinia stores:
// stores/navigation.js
import { defineStore } from 'pinia'
import { useRouter, useRoute } from 'vue-router'
export const useNavigationStore = defineStore('navigation', () => {
const router = useRouter()
const route = useRoute()
const currentRouteName = computed(() => route.name)
function navigateTo(routeName) {
router.push({ name: routeName })
}
return {
currentRouteName,
navigateTo
}
})
Reactive Route Parameters
Leveraging Vue's reactivity system, you can create reactive states based on route parameters:
import { useRoute } from 'vue-router'
import { ref, watch } from 'vue'
export default {
setup() {
const route = useRoute()
const postId = ref(route.params.id)
watch(
() => route.params.id,
(newId) => {
postId.value = newId
loadPost(newId)
}
)
return {
postId
}
}
}
Route Lazy Loading with Composition API
Combining route lazy loading with Composition API for more efficient code splitting:
import { defineAsyncComponent } from 'vue'
const routes = [
{
path: '/dashboard',
component: defineAsyncComponent(() =>
import('@/views/Dashboard.vue')
),
meta: { requiresAuth: true }
}
]
Mocking Routes in Tests
Mocking routes in component tests:
import { mount } from '@vue/test-utils'
import { useRoute, useRouter } from 'vue-router'
jest.mock('vue-router', () => ({
useRoute: jest.fn(),
useRouter: jest.fn()
}))
test('Testing route-related functionality', () => {
useRoute.mockImplementation(() => ({
params: { id: '123' }
}))
const push = jest.fn()
useRouter.mockImplementation(() => ({
push
}))
const wrapper = mount(Component)
wrapper.find('button').trigger('click')
expect(push).toHaveBeenCalledWith('/expected-path')
})
Route Transition Animations
Combining routes with transition animations:
import { useRoute } from 'vue-router'
import { ref, watch } from 'vue'
export default {
setup() {
const route = useRoute()
const transitionName = ref('fade')
watch(
() => route.meta.transition,
(newTransition) => {
transitionName.value = newTransition || 'fade'
}
)
return {
transitionName
}
}
}
Scroll Behavior Control
Customizing scroll behavior:
import { useRouter } from 'vue-router'
export default {
setup() {
const router = useRouter()
router.options.scrollBehavior = (to, from, savedPosition) => {
if (savedPosition) {
return savedPosition
} else if (to.hash) {
return { el: to.hash }
} else {
return { top: 0 }
}
}
}
}
Route Error Handling
Handling navigation errors:
import { useRouter } from 'vue-router'
export default {
setup() {
const router = useRouter()
const navigateSafely = async (path) => {
try {
await router.push(path)
} catch (error) {
if (error.name === 'NavigationDuplicated') {
// Handle duplicate navigation error
} else {
// Handle other navigation errors
}
}
}
return {
navigateSafely
}
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:路由元信息类型推断
下一篇:仪表盘(Gauge)实现