Quasar框架路由传参企业级实用教程文档
Quasar框架路由传参企业级实用教程文档
一、Quasar路由基础
Quasar使用Vue Router作为路由系统,路由配置通常在src/router/routes.js中定义,支持参数传递、嵌套路由等企业级特性。
基础路由配置示例
// src/router/routes.js
const routes = [
{
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{
path: 'dashboard',
component: () => import('pages/Dashboard.vue'),
meta: { requiresAuth: true }
},
// 带参数的路由
{
path: 'user/:id',
component: () => import('pages/UserProfile.vue'),
props: true // 关键配置:启用props接收参数
},
// 多参数路由
{
path: 'project/:projectId/task/:taskId',
component: () => import('pages/ProjectTask.vue'),
props: true
}
]
}
]
二、路由传参的三种主要方式
1. 路径参数(Params)
适用场景:必须参数,如ID、标识符等核心业务数据
路由配置
{
path: 'user/:userId',
name: 'UserProfile',
component: () => import('pages/UserProfile.vue'),
props: true // 启用props接收
}
参数传递方式
// 方式1:使用路径字符串
router.push('/user/12345')
// 方式2:使用命名路由(推荐)
router.push({
name: 'UserProfile',
params: { userId: '12345' }
})
组件接收参数
<script setup lang="ts">
// 类型安全的参数接收
defineProps<{
userId: string
}>()
</script>
2. 查询参数(Query)
适用场景:可选参数,如过滤条件、分页信息、排序方式等
参数传递方式
// 方式1:路径字符串
router.push('/search?q=quasar&page=2')
// 方式2:对象形式(推荐)
router.push({
path: '/search',
query: {
q: 'quasar',
page: '2',
filter: 'active'
}
})
组件接收参数
<script setup lang="ts">
import { useRoute } from 'vue-router'
import { computed } from 'vue'
const route = useRoute()
// 响应式查询参数访问
const searchTerm = computed(() => route.query.q as string)
const currentPage = computed(() => parseInt(route.query.page as string || '1'))
</script>
3. Props传参(企业级推荐方式)
适用场景:复杂参数处理,保持组件与路由系统解耦
路由配置
{
path: 'project/:projectId/task/:taskId',
name: 'ProjectTask',
component: () => import('pages/ProjectTask.vue'),
props: (route) => ({
projectId: route.params.projectId,
taskId: route.params.taskId,
viewMode: route.query.mode || 'default', // 合并query参数
isEditMode: route.query.edit === 'true'
})
}
组件接收参数
<script setup lang="ts">
// 定义完整类型接口
interface ProjectTaskProps {
projectId: string
taskId: string
viewMode: 'default' | 'compact' | 'detailed'
isEditMode: boolean
}
// 类型安全接收
const props = defineProps<ProjectTaskProps>()
</script>
三、多参数传递的企业级实践
复杂场景实现:项目任务详情页
需要传递项目ID、任务ID、查看模式和编辑状态等复合参数
路由配置(带参数验证)
{
path: 'project/:projectId/task/:taskId',
name: 'ProjectTaskDetail',
component: () => import('pages/ProjectTaskDetail.vue'),
// 使用路由props函数处理复杂参数
props: (route) => ({
projectId: validateId(route.params.projectId),
taskId: validateId(route.params.taskId),
viewMode: route.query.mode as 'compact' | 'detailed' || 'detailed',
isEditing: route.query.edit === 'true'
})
}
// 参数验证函数
function validateId(id: unknown): string {
if (typeof id === 'string' && /^\d+$/.test(id)) {
return id
}
throw new Error(`Invalid ID: ${id}`)
}
组件实现(完整功能)
<script setup lang="ts">
import { onMounted, watch, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
// 定义类型化props
interface TaskDetailProps {
projectId: string
taskId: string
viewMode: 'compact' | 'detailed'
isEditing: boolean
}
const props = defineProps<TaskDetailProps>()
const route = useRoute()
const router = useRouter()
// 更新URL参数的方法
function updateQueryParams(params: Record<string, string>) {
router.push({
name: 'ProjectTaskDetail',
params: {
projectId: props.projectId,
taskId: props.taskId
},
query: {
...route.query,
...params
}
})
}
// 切换编辑模式
function toggleEditMode() {
updateQueryParams({
edit: String(!props.isEditing)
})
}
// 切换视图模式
function setViewMode(mode: 'compact' | 'detailed') {
updateQueryParams({
mode
})
}
// 监听参数变化
watch(
() => [props.projectId, props.taskId],
([newProjectId, newTaskId]) => {
// 重新加载数据
loadTaskData(newProjectId, newTaskId)
},
{ immediate: true } // 初始加载时执行
)
// 初始化加载
onMounted(() => {
loadTaskData(props.projectId, props.taskId)
})
// 数据加载函数
async function loadTaskData(projectId: string, taskId: string) {
// 实际项目中这里会调用API加载数据
console.log(`Loading task ${taskId} from project ${projectId}`)
}
</script>
四、企业级最佳实践
1. 参数验证与类型安全
// 创建参数验证工具函数
import { RouteLocationNormalized } from 'vue-router'
export function parseRouteParams<T>(route: RouteLocationNormalized, validator: (params: any) => T): T {
try {
return validator(route.params)
} catch (error) {
console.error('Invalid route parameters', error)
throw new Error('Invalid route parameters')
}
}
// 使用示例
const taskParamsValidator = (params: any) => {
if (params && typeof params === 'object') {
const p = params as Record<string, unknown>
if (typeof p.projectId === 'string' && typeof p.taskId === 'string') {
return {
projectId: p.projectId,
taskId: p.taskId
}
}
}
throw new Error('Invalid task parameters')
}
// 在组件中使用
const route = useRoute()
const { projectId, taskId } = parseRouteParams(route, taskParamsValidator)
2. 路由守卫中的参数验证
// 在路由守卫中验证参数合法性
router.beforeEach((to, from, next) => {
if (to.name === 'ProjectTaskDetail') {
try {
// 验证项目ID格式
if (!/^PROJ-\d{4}$/.test(to.params.projectId as string)) {
throw new Error('Invalid project ID format')
}
// 验证任务ID存在性(可调用API或状态管理)
if (!taskExists(to.params.projectId, to.params.taskId)) {
return next({ name: 'NotFound' })
}
} catch (error) {
// 记录错误日志
logError(error)
return next({ name: 'InvalidParams' })
}
}
next()
})
3. 复杂对象参数传递方案
// 对象编码工具函数
function encodeObject(obj: Record<string, any>): string {
return btoa(JSON.stringify(obj))
}
function decodeObject<T>(str: string): T {
return JSON.parse(atob(str))
}
// 传递复杂过滤条件
router.push({
path: '/reports',
query: {
filters: encodeObject({
dateRange: ['2023-01-01', '2023-12-31'],
departments: ['finance', 'hr'],
status: 'completed'
})
}
})
// 接收端解码处理
const route = useRoute()
const filters = computed(() => {
try {
return route.query.filters
? decodeObject<ReportFilters>(route.query.filters as string)
: defaultFilters
} catch (e) {
return defaultFilters
}
})
4. 路由参数变化响应式处理
<script setup lang="ts">
import { watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
// 监听特定参数变化
watch(
() => route.params.projectId,
(newProjectId) => {
if (newProjectId) {
loadProjectData(newProjectId)
}
},
{ immediate: true } // 立即执行一次
)
// 监听查询参数变化
watch(
() => route.query.view,
(newViewMode) => {
if (newViewMode) {
setViewMode(newViewMode as ViewMode)
}
}
)
</script>
5. 路由状态持久化方案
// 保存路由状态到本地存储
router.afterEach((to) => {
localStorage.setItem('lastRouteState', JSON.stringify({
name: to.name,
params: to.params,
query: to.query
}))
})
// 应用启动时恢复路由状态
const savedRoute = localStorage.getItem('lastRouteState')
if (savedRoute) {
try {
const { name, params, query } = JSON.parse(savedRoute)
router.replace({ name, params, query })
} catch (error) {
console.error('Failed to restore route state', error)
}
}
五、常见问题解决方案
问题1:刷新页面后参数丢失
解决方案:使用路由props代替组件内直接访问$route.params
// 路由配置
{
path: '/user/:userId',
component: UserProfile,
props: true // 关键配置
}
// 组件中
defineProps(['userId']) // 直接使用props
问题2:可选参数处理
解决方案:使用可选参数语法和默认值
// 路由配置
{
path: '/user/:userId/:tab?', // 可选参数
props: (route) => ({
userId: route.params.userId,
tab: route.params.tab || 'profile' // 默认值
})
}
问题3:参数类型转换
解决方案:在props函数中处理类型转换
props: (route) => ({
projectId: Number(route.params.projectId),
page: parseInt(route.query.page as string) || 1,
isActive: route.query.status === 'active'
})
六、企业级路由传参架构图
┌──────────────────────┐ ┌──────────────────────┐
│ 路由配置 │ │ 组件使用 │
│ │ │ │
│ - 路径参数定义 ├───────► defineProps接收 │
│ - props: true │ │ - 类型安全 │
│ - props函数 │ │ - 响应式更新 │
└──────────┬───────────┘ └──────────▲───────────┘
│ │
│ │
│ │
┌──────────▼───────────┐ ┌──────────┴───────────┐
│ 参数传递 │ │ 状态管理 │
│ │ │ │
│ - router.push │ │ - Pinia存储 │
│ - router.replace │ │ - 复杂状态持久化 │
│ - <router-link> │ └──────────────────────┘
└──────────────────────┘
七、企业级路由传参原则总结
1. 优先使用props传递参数:保持组件与路由系统解耦,增强可测试性
2. 严格类型检查:使用TypeScript定义参数接口,确保类型安全
3. 参数验证:在路由守卫和组件中双重验证参数合法性
4. 合理选择传参方式:
o 核心业务数据 → 路径参数(Params)
o 可选配置信息 → 查询参数(Query)
o 复杂对象数据 → 状态管理 + URL编码
5. 响应式处理:正确监听参数变化并更新组件状态
6. 状态持久化:关键路由状态本地存储,提升用户体验
通过遵循以上实践,可构建健壮、可维护的企业级Quasar应用路由系统,有效支持各种复杂业务场景的参数传递需求。