routeLocationKey - 路由位置键
routeLocationKey 是一个Symbol类型的常量,用于在 Vue 的依赖注入系统中标识当前的路由位置信息。它是访问路由状态的核心注入键之一。📍
📋 变量定义
typescript
const routeLocationKey: InjectionKey<RouteLocationNormalized>🎯 功能说明
这个变量提供了对当前路由位置的完整访问能力:
- 依赖注入键 - 用于在组件树中注入当前路由位置
- 完整路由信息 - 包含路径、参数、查询、哈希等所有路由数据
- 类型安全 - 提供完整的 TypeScript 类型支持
🔧 技术细节
类型定义
typescript
// routeLocationKey 的完整类型
const routeLocationKey: InjectionKey<RouteLocationNormalized>
// 对应的注入值类型(RouteLocationNormalized)
interface RouteLocationNormalized {
path: string // 路径
fullPath: string // 完整路径(包含查询和哈希)
params: RouteParams // 路径参数
query: LocationQuery // 查询参数
hash: string // 哈希值
name?: RouteRecordName // 路由名称
matched: RouteRecordNormalized[] // 匹配的路由记录
meta: RouteMeta // 路由元数据
redirectedFrom?: RouteLocation // 重定向来源
}在 Vue Router 中的使用
typescript
// Vue Router 内部组件使用示例
export default defineComponent({
inject: {
routeLocation: { from: routeLocationKey }
},
setup(props, { injections }) {
const route = injections.routeLocation as RouteLocationNormalized
// 使用当前路由位置信息
}
})💡 实际应用示例
基础路由信息访问
vue
<script setup>
import { routeLocationKey } from 'vue-router'
import { inject, computed } from 'vue'
// 注入当前路由位置
const routeLocation = inject(routeLocationKey)
// 计算常用的路由信息
const routeInfo = computed(() => ({
currentPath: routeLocation?.path,
fullPath: routeLocation?.fullPath,
params: routeLocation?.params || {},
query: routeLocation?.query || {},
hash: routeLocation?.hash,
routeName: routeLocation?.name
}))
// 检查特定条件
const isProductPage = computed(() =>
routeLocation?.path?.startsWith('/product/')
)
const hasSearchQuery = computed(() =>
routeLocation?.query?.q !== undefined
)
</script>
<template>
<div class="route-info">
<h4>当前路由信息</h4>
<p>路径: {{ routeInfo.currentPath }}</p>
<p>完整路径: {{ routeInfo.fullPath }}</p>
<p>参数: {{ JSON.stringify(routeInfo.params) }}</p>
<p>查询: {{ JSON.stringify(routeInfo.query) }}</p>
<div v-if="isProductPage" class="product-badge">
产品页面
</div>
</div>
</template>高级路由监控组件
vue
<script setup>
import { routeLocationKey } from 'vue-router'
import { inject, watch, ref } from 'vue'
const routeLocation = inject(routeLocationKey)
// 路由变化历史记录
const routeHistory = ref([])
// 监听路由变化
watch(routeLocation, (newRoute, oldRoute) => {
if (newRoute && oldRoute) {
routeHistory.value.push({
from: oldRoute.path,
to: newRoute.path,
timestamp: new Date().toISOString(),
queryChanged: newRoute.query !== oldRoute.query,
paramsChanged: newRoute.params !== oldRoute.params
})
// 保持最近10条记录
if (routeHistory.value.length > 10) {
routeHistory.value.shift()
}
}
}, { immediate: true })
// 路由统计信息
const routeStats = ref({
totalVisits: 0,
uniquePaths: new Set(),
queryUsage: {}
})
// 更新统计信息
watch(routeLocation, (newRoute) => {
if (newRoute) {
routeStats.value.totalVisits++
routeStats.value.uniquePaths.add(newRoute.path)
// 统计查询参数使用情况
Object.keys(newRoute.query).forEach(key => {
routeStats.value.queryUsage[key] =
(routeStats.value.queryUsage[key] || 0) + 1
})
}
})
</script>
<template>
<div class="route-monitor">
<h4>路由监控</h4>
<div class="stats">
<p>总访问: {{ routeStats.totalVisits }}</p>
<p>唯一路径: {{ routeStats.uniquePaths.size }}</p>
</div>
<div class="history">
<h5>最近路由变化</h5>
<div
v-for="(record, index) in routeHistory"
:key="index"
class="history-item"
>
{{ record.from }} → {{ record.to }}
</div>
</div>
</div>
</template>路由感知的表单组件
vue
<script setup>
import { routeLocationKey } from 'vue-router'
import { inject, computed, watch } from 'vue'
const routeLocation = inject(routeLocationKey)
// 从路由参数初始化表单数据
const formData = ref({
category: routeLocation?.params.category || '',
search: routeLocation?.query.q || '',
page: Number(routeLocation?.query.page) || 1,
sort: routeLocation?.query.sort || 'name'
})
// 当路由变化时更新表单数据
watch(routeLocation, (newRoute) => {
if (newRoute) {
formData.value = {
category: newRoute.params.category || '',
search: newRoute.query.q || '',
page: Number(newRoute.query.page) || 1,
sort: newRoute.query.sort || 'name'
}
}
})
// 当表单数据变化时更新路由
watch(formData, (newData, oldData) => {
if (JSON.stringify(newData) !== JSON.stringify(oldData)) {
// 构建新的查询参数
const query = {
...routeLocation?.query,
q: newData.search || undefined,
page: newData.page > 1 ? newData.page.toString() : undefined,
sort: newData.sort !== 'name' ? newData.sort : undefined
}
// 清理空值
Object.keys(query).forEach(key => {
if (query[key] === undefined || query[key] === '') {
delete query[key]
}
})
// 更新路由(不触发组件重新挂载)
router.push({
path: routeLocation?.path,
query
})
}
}, { deep: true, immediate: false })
</script>
<template>
<form class="search-form">
<input
v-model="formData.search"
placeholder="搜索..."
type="search"
/>
<select v-model="formData.category">
<option value="">所有分类</option>
<option value="electronics">电子产品</option>
<option value="books">图书</option>
</select>
<select v-model="formData.sort">
<option value="name">按名称</option>
<option value="price">按价格</option>
<option value="date">按日期</option>
</select>
<button type="submit">搜索</button>
</form>
</template>🎯 使用场景
面包屑导航组件
vue
<script setup>
import { routeLocationKey } from 'vue-router'
import { inject, computed } from 'vue'
const routeLocation = inject(routeLocationKey)
// 生成面包屑导航数据
const breadcrumbs = computed(() => {
if (!routeLocation?.matched) return []
return routeLocation.matched.map((route, index) => {
const isLast = index === routeLocation.matched.length - 1
return {
name: route.meta?.breadcrumb || route.name || route.path,
path: isLast ? null : generatePath(route, routeLocation.params),
active: isLast
}
})
})
// 生成路径(处理动态参数)
function generatePath(route, params) {
let path = route.path
// 替换路径参数
Object.keys(params).forEach(key => {
path = path.replace(`:${key}`, params[key])
})
return path
}
</script>
<template>
<nav class="breadcrumb">
<router-link
v-for="(crumb, index) in breadcrumbs"
:key="index"
:to="crumb.path"
:class="{ active: crumb.active }"
class="breadcrumb-item"
>
{{ crumb.name }}
<span v-if="!crumb.active" class="separator">/</span>
</router-link>
</nav>
</template>页面标题管理
vue
<script setup>
import { routeLocationKey } from 'vue-router'
import { inject, watch } from 'vue'
const routeLocation = inject(routeLocationKey)
// 根据路由动态设置页面标题
watch(routeLocation, (newRoute) => {
if (newRoute) {
const titleParts = []
// 添加路由元数据中的标题
if (newRoute.meta?.title) {
titleParts.push(newRoute.meta.title)
}
// 添加路由名称(如果没有元数据标题)
else if (newRoute.name) {
titleParts.push(newRoute.name)
}
// 添加站点名称
titleParts.push('我的应用')
// 设置文档标题
document.title = titleParts.join(' - ')
}
}, { immediate: true })
</script>
<template>
<!-- 这个组件不需要模板,它只负责设置页面标题 -->
</template>🔧 实用工具函数
路由信息工具
typescript
// 提供便捷的路由信息访问
export function useRouteLocation() {
const routeLocation = inject(routeLocationKey)
return {
// 基础信息
path: routeLocation?.path,
fullPath: routeLocation?.fullPath,
name: routeLocation?.name,
// 参数访问
params: routeLocation?.params || {},
query: routeLocation?.query || {},
hash: routeLocation?.hash,
// 便捷方法
hasParam: (key: string) => key in (routeLocation?.params || {}),
getParam: (key: string) => routeLocation?.params?.[key],
hasQuery: (key: string) => key in (routeLocation?.query || {}),
getQuery: (key: string) => routeLocation?.query?.[key],
// 验证方法
isCurrentRoute: (path: string) => routeLocation?.path === path,
matchesPattern: (pattern: RegExp) => pattern.test(routeLocation?.path || '')
}
}
// 使用示例
const { path, hasQuery, getQuery } = useRouteLocation()🔗 相关变量
matchedRouteKey- 匹配路由注入键routerKey- 路由实例注入键START_LOCATION- 起始位置常量
💡 专业建议:虽然可以直接使用
routeLocationKey进行依赖注入,但在大多数情况下,使用useRoute()组合式 API 是更简单和推荐的方式,它提供了相同的功能但更易于使用。