Vue3 零基础每日笔记(047):动态路由与路由参数——:id 传参、query 传参、props 解耦

一、前言

详情页是所有应用的基本盘:商品详情、用户主页、订单明细------URL 里必须带"这一条数据是谁"的信息。本篇讲透三种传参方式:路径参数(:id)、查询参数(query)、props 解耦,以及新手必踩的"参数变了页面不刷新"大坑。

三种传参先混个脸熟

text 复制代码
/user/1                  → 路径参数:params.id = '1'(RESTful 风格,详情页标配)
/user?id=1               → 查询参数:query.id = '1'(列表筛选、搜索词)
props 解耦               → 前两种的"接收方式升级",组件不依赖 useRoute

二、路径参数:动态路由 :id

路由表里用 :参数名 声明"这个位置是可变的":

ts 复制代码
// src/router/index.ts
const routes = [
  {
    path: '/user/:id',          // :id 是动态段------/user/1、/user/2、/user/abc 都匹配
    name: 'user',
    component: () => import('@/views/UserView.vue')
  }
]
vue 复制代码
<!-- src/views/UserView.vue -->
<template>
  <h2>用户详情页</h2>
  <p>URL 是:{{ route.fullPath }}</p>
  <p>params.id = {{ route.params.id }}</p>
</template>

<script setup lang="ts">
import { useRoute } from 'vue-router'

const route = useRoute()
// 注意类型:params 的值是 string | string[],不是 number!
const id = route.params.id
console.log(typeof id)   // string
</script>

访问 /user/42route.params.id 得到字符串 '42'要数字自己转

ts 复制代码
const id = Number(route.params.id)
if (Number.isNaN(id)) {
  // 非法参数处理:跳 404 或提示
}

可选参数?path: '/user/:id?'------/user/user/1 都能匹配,用时记得判空。

【截图位置:访问 /user/42 显示参数的运行效果】

三、大坑登场:参数变了,页面却不刷新

复现现场:在详情页放一个"看下一位用户"的按钮:

vue 复制代码
<template>
  <p>当前用户:{{ route.params.id }}</p>
  <!-- 模板里 route.params 是响应式的,这里会更新 -->
  <RouterLink :to="`/user/${Number(route.params.id) + 1}`">下一位 →</RouterLink>
</template>

问题来了:如果页面数据是"进页面时用 onMounted 拉取的",点击链接 URL 变了,数据却不动

原因:/user/1/user/2 匹配的是同一个路由 ,Vue Router 出于性能默认复用组件实例------组件不会重新创建,onMounted 不再执行(011 篇生命周期知识联动)。

解法 1:watch 监听参数(推荐,最常用)

ts 复制代码
import { watch } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()

// 进页面执行一次 + 参数变了再执行(immediate)
watch(
  () => route.params.id,
  (newId) => {
    if (newId) loadData(Number(newId))
  },
  { immediate: true }
)

function loadData(id: number) {
  console.log('加载用户', id, '的数据')
}

解法 2:router-view 上加 key,强制重建组件(简单粗暴)

vue 复制代码
<!-- App.vue -->
<RouterView :key="route.fullPath" />

URL 一变组件销毁重建,onMounted 重新执行------代价是整个页面全部重渲染,页面轻可用,页面重慎用。默认学解法 1。

四、query 查询参数:筛选与搜索的地盘

query 不需要路由表声明,拼在 URL 后面就能读:

ts 复制代码
// 跳转:/search?kw=vue3&page=2
router.push({ name: 'search', query: { kw: 'vue3', page: 2 } })

// 读取(045 篇的 search 页)
const kw = route.query.kw        // 'vue3',类型 LocationQueryValue = string | null
const page = Number(route.query.page ?? 1)

params vs query 对比表

params(路径参数) query(查询参数)
URL 长相 /user/1 /user?id=1
路由表 必须声明 :id 不需要声明
语义 这条资源的"身份" 查询条件/视图状态
典型场景 详情页 ID 搜索词、页码、筛选条件
刷新后 保留(在 URL 里) 保留(在 URL 里)

记忆:身份进路径,条件进 query

五、props 解耦:组件不再依赖 useRoute

问题:UserView 里到处 route.params.id,组件和路由器耦合死了,想单独复用/测试很难。路由配置提供 props 选项,把参数变成正经 props:

ts 复制代码
// 路由配置加 props: true
{
  path: '/user/:id',
  name: 'user',
  component: () => import('@/views/UserView.vue'),
  props: true   // 把 params 作为 props 传给组件
}
vue 复制代码
<!-- UserView.vue:改用 props 接收,和普通组件毫无区别 -->
<template>
  <p>用户 ID:{{ id }}(类型 {{ typeof id }})</p>
</template>

<script setup lang="ts">
// 不再需要 useRoute!
defineProps<{ id: string }>()
</script>

props 三种模式

ts 复制代码
props: true                                  // 布尔模式:params 全量转 props
props: { id: 123 }                           // 对象模式:静态值(少用)
props: (route) => ({ id: Number(route.params.id) })  // 函数模式:自由加工(转数字常用)

函数模式是实战首选------顺手把字符串转成数字,组件拿到的就是干净的 number:

vue 复制代码
<script setup lang="ts">
defineProps<{ id: number }>()   // 函数模式加工后,直接是数字
</script>

六、综合实战:用户列表 → 详情 → 参数联动

三个文件走通全链路:

ts 复制代码
// src/router/index.ts 追加
{
  path: '/users',
  name: 'users',
  component: () => import('@/views/UserListView.vue')
},
{
  path: '/user/:id',
  name: 'user',
  component: () => import('@/views/UserDetailView.vue'),
  props: (route) => ({ id: Number(route.params.id) })
}
vue 复制代码
<!-- src/views/UserListView.vue:列表 + 声明式跳转 -->
<template>
  <h2>用户列表</h2>
  <ul>
    <li v-for="u in users" :key="u.id">
      <RouterLink :to="{ name: 'user', params: { id: u.id } }">
        {{ u.name }}
      </RouterLink>
    </li>
  </ul>
</template>

<script setup lang="ts">
const users = [
  { id: 1, name: '小明' },
  { id: 2, name: '小红' },
  { id: 3, name: '小刚' }
]
</script>
vue 复制代码
<!-- src/views/UserDetailView.vue:props 接参 + watch 响应参数变化 -->
<template>
  <h2>用户详情:ID = {{ id }}</h2>
  <p>模拟数据:{{ detail }}</p>
  <button @click="next">下一位用户 →(参数变化,页面不重建)</button>
  <RouterLink to="/users">← 回列表</RouterLink>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import { useRouter } from 'vue-router'

// 函数模式加工过,id 是干净的 number
const props = defineProps<{ id: number }>()
const router = useRouter()

const detail = ref('')

function load(uid: number) {
  // 模拟请求详情
  detail.value = `这是用户 ${uid} 的详细信息`
}

// 组件复用不重建 → 用 watch 响应参数变化(解法 1)
watch(() => props.id, load, { immediate: true })

function next() {
  router.push({ name: 'user', params: { id: props.id + 1 } })
}
</script>

全链路品味:列表按 name 跳转带 params → 详情页函数模式把 id 加工成 number → watch immediate 首次加载 + 参数变化重载。

【截图位置:列表进详情、点"下一位"数据联动更新的运行效果】

七、踩坑记录

  1. params 是字符串route.params.id + 1 得到 '11'(字符串拼接)------Number() 转换或用 props 函数模式加工
  2. 同路由参数变化组件不重建:onMounted 的数据请求只跑一次------watch 参数(推荐)或 RouterView 加 key(粗暴)
  3. query 值可能是数组 :同名参数出现多次时 ?a=1&a=2,route.query.a 变数组------读取时统一处理成数组或取第一个
  4. 可选参数忘了判空:id? 匹配 /user 时 params.id 是 '' 或 undefined------使用前判断
  5. props: true 后组件里还去 useRoute:能跑但白解耦了------选了 props 模式就贯彻到底
  6. 404 误伤:/user/abc 也会匹配 :id------非法值在页面里判断后跳转 404(052 篇配 catchAll)

八、今日小结

  • 动态路由 :id 声明动态段,params 取值是字符串要转数字
  • 同路由参数变化默认复用组件:watch 参数(immediate)是标准解法
  • params 管身份、query 管条件;name 配 params、path 配 query
  • props 解耦三模式,函数模式最实用(顺手转数字)

下篇预告

后台管理系统长什么样?顶部栏 + 侧边菜单 + 内容区,菜单里还能再开子页面。下一篇 048 嵌套路由与命名视图------children 配置搭出后台布局雏形。

相关推荐
计算机毕设定制辅导-无忧学长1 小时前
《基于SpringBoot的中学教师数字胜任力测评网站的设计与实现》
java·vue.js·spring boot·mysql·中学教师数字胜任力测评网站
黑马程序员毕设1 小时前
基于微信小程序的二手交易平台设计与实现报告
前端·人工智能·spring boot·后端·考研
cAuth2 小时前
实现一个图形编辑器
前端·架构·计算机图形学
沪上企服通2 小时前
旧账系统的信创迁移工程:从 MySQL/Oracle 到国产库、国密与电子会计档案闭环
数据库·笔记·数据库架构
Nayana2 小时前
《Web 到 HarmonyOS》-- 嵌入 Web 与桥接基础
前端
一拳不是超人2 小时前
之前用 AI 两小时写的塔罗网站,我真把它做上线了,然后呢?
前端·人工智能·程序员
三岁就很~酷~3 小时前
ai agent自学 基础命令和上下文监控(9/17)
笔记
flash俊杰3 小时前
ASR 转写与字幕时间轴:强制对齐、CPS 约束与 SRT 工程化
前端