Quasar框架路由传参企业级实用教程
# Quasar框架路由传参企业级实用教程
## 一、Quasar路由基础
Quasar使用Vue Router作为其路由系统,因此路由传参完全遵循Vue Router的规范。在Quasar项目中,路由配置通常在`src/router/routes.js`中定义。
### 路由配置示例:
```javascript
// 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、标识符等
#### 配置路由:
```javascript
{
path: 'user/:userId',
name: 'UserProfile',
component: () => import('pages/UserProfile.vue'),
props: true // 启用props接收
}
```
#### 传递参数:
```javascript
// 使用路径
router.push('/user/12345')
// 使用命名路由
router.push({
name: 'UserProfile',
params: { userId: '12345' }
})
```
#### 接收参数:
```vue
<script setup lang="ts">
// 在组件中接收
defineProps<{
userId: string
}>()
</script>
```
### 2. 查询参数(Query)
**适用场景**:可选参数,如过滤条件、分页信息等
#### 传递参数:
```javascript
// 使用路径
router.push('/search?q=quasar&page=2')
// 使用对象形式
router.push({
path: '/search',
query: {
q: 'quasar',
page: '2',
filter: 'active'
}
})
```
#### 接收参数:
```vue
<script setup lang="ts">
import { useRoute } from 'vue-router'
const route = useRoute()
// 访问查询参数
const searchTerm = computed(() => route.query.q as string)
const currentPage = computed(() => parseInt(route.query.page as string || '1'))
</script>
```
### 3. Props传参(推荐方式)
**适用场景**:企业级应用最佳实践,保持组件解耦
#### 路由配置:
```javascript
{
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参数
})
}
```
#### 组件接收:
```vue
<script setup lang="ts">
interface ProjectTaskProps {
projectId: string
taskId: string
viewMode: 'default' | 'compact' | 'detailed'
}
defineProps<ProjectTaskProps>()
</script>
```
## 三、多参数传递的企业级实践
### 场景:项目任务详情页
需要传递:项目ID、任务ID、查看模式和编辑状态
#### 路由配置:
```javascript
{
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 || '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}`)
}
```
#### 组件实现:
```vue
<script setup lang="ts">
import { onMounted, watch } 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 router = useRouter()
// 监听参数变化
watch(
() => [props.projectId, props.taskId],
([newProjectId, newTaskId]) => {
// 重新加载数据
loadTaskData(newProjectId, newTaskId)
}
)
// 更新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
})
}
// 初始化加载
onMounted(() => {
loadTaskData(props.projectId, props.taskId)
})
</script>
```
## 四、企业级最佳实践
### 1. 参数验证与类型安全
```typescript
// 创建参数验证工具
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: unknown) => {
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. 路由守卫中的参数处理
```javascript
// 在路由守卫中验证参数
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存在性
if (!taskExists(to.params.projectId, to.params.taskId)) {
return next({ name: 'NotFound' })
}
} catch (error) {
// 记录错误日志
logError(error)
return next({ name: 'InvalidParams' })
}
}
next()
})
```
### 3. 复杂对象参数传递
对于复杂对象,推荐使用状态管理或URL编码:
```javascript
// 对象编码工具
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. 路由参数变化响应
```vue
<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. 路由参数持久化
```javascript
// 保存路由状态到本地存储
router.afterEach((to) => {
localStorage.setItem('lastRouteState', JSON.stringify({
name: to.name,
params: to.params,
query: to.query
}))
})
// 应用启动时恢复
const savedRoute = localStorage.getItem('lastRouteState')
if (savedRoute) {
const { name, params, query } = JSON.parse(savedRoute)
router.replace({ name, params, query })
}
```
## 五、常见问题解决方案
### 问题1:刷新页面后参数丢失
**解决方案**:使用路由props代替组件内直接访问`$route.params`
```javascript
// 路由配置
props: true
// 组件中
defineProps(['userId'])
```
### 问题2:可选参数处理
**解决方案**:使用可选参数语法和默认值
```javascript
// 路由配置
{
path: '/user/:userId/:tab?', // 可选参数
props: (route) => ({
userId: route.params.userId,
tab: route.params.tab || 'profile' // 默认值
})
}
```
### 问题3:参数类型转换
**解决方案**:在props函数中处理类型转换
```javascript
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> │ └──────────────────────┘
└──────────────────────┘
```
## 七、总结
在Quasar框架中实现企业级路由传参应遵循以下原则:
1. **优先使用props传递参数**:保持组件解耦,增强可测试性
2. **严格类型检查**:使用TypeScript确保参数类型安全
3. **参数验证**:在路由守卫和组件中进行参数验证
4. **响应式处理**:正确监听路由参数变化
5. **合理选择传参方式**:
- 必要标识符 → 路径参数
- 可选配置 → 查询参数
- 复杂对象 → 状态管理 + URL编码
6. **持久化重要状态**:确保刷新后用户体验一致
通过遵循这些实践,您可以构建出健壮、可维护的企业级Quasar应用路由系统,有效处理简单和复杂的路由参数场景。