Code前端首页关于Code前端联系我们

params参数到底是什么?

terry 3周前 (09-07) 阅读数 43 #Vue
文章标签 params;参数

p>刚开始学vue - router的时候,很多人对params参数一头雾水——明明按教程写了传参代码,怎么页面刷新就丢数据?动态路由里的params和普通传参有啥区别?和query参数到底该选哪个?今天咱们就把params的用法、坑点、实战场景掰开了揉碎了讲,新手也能秒懂~

你可以把params理解成路由里的“动态变量”,它和路由规则绑定得特别紧,比如要做个商品详情页,每个商品有唯一id,路由规则写成path: '/product/:productId',这里的:productId就是给params留的位置,以后访问/product/123时,productId就会被解析成params里的键值对({ productId: '123' })。

但params不止这一种玩法——就算路由规则里没写:xxx这种动态段,用命名路由传参时也能塞params(比如this.$router.push({ name: 'About', params: { msg: 'hello' } })),不过这种情况下,params更像“临时搭车”的参数,和路由路径本身没直接绑定,后面刷新页面容易出问题,这点后面会详细说。

怎么给路由传params参数?(两种核心方式)

传params主要分“动态路由直接嵌”“命名路由带参数”两种玩法,用法不同,坑点也不一样,得仔细看~

动态路由传参(路由配置带动态段)

先在路由规则里写好动态占位符,比如要做用户页,每个用户id不同,路由配置成这样:

{
  path: '/user/:userId', // 这里:userId是动态段
  name: 'User',
  component: User
}

然后跳转的时候,有两种写法:

  • <router - link>组件,动态拼接路径:

    <router - link :to="`/user/${userId}`">去用户页</router - link>
  • 用编程式导航(比如按钮点击事件里):

    this.$router.push(`/user/${this.userId}`) // Vue2写法

这种方式下,params是路由路径的一部分,所以URL里会明明白白显示/user/123,刷新页面也不会丢数据(因为URL里存着参数呢)。

命名路由+params传参(路由没动态段时要注意)

如果路由规则里没写动态段,比如一个关于我们的页面:

{
  path: '/about',
  name: 'About',
  component: About
}

这时候想传参数,得用命名路由+params对象的方式:

this.$router.push({ 
  name: 'About', 
  params: { msg: '这是传给About页的消息' } 
})

这种传法有个隐藏雷区刷新页面后,params里的参数会直接消失!为啥?因为params没被写进URL里,浏览器刷新时,路由重新匹配,系统根本不知道之前传了啥参数,自然就丢了,所以这种传法适合“参数临时用、刷新后重置也没关系”的场景,比如页面内的临时状态传递。

页面怎么接收params参数?

传完参数,页面得能拿到值才行,接收方式分两种情况,取决于你是用动态路由传参,还是命名路由传参~

动态路由下的接收(路由有:xxx这种)

不管是Vue2还是Vue3,都通过当前路由对象来拿params。

  • Vue2里,在组件中用this.$route.params.xxx

    export default {
    created() {
      console.log(this.$route.params.productId) // 比如拿商品id
    }
    }
  • Vue3里,得用useRoute这个组合式API:

    import { useRoute } from 'vue - router'
    export default {
    setup() {
      const route = useRoute()
      console.log(route.params.productId)
      return {}
    }
    }

命名路由传参但路由无动态段的接收

这种情况接收方式和上面一样,也是this.$route.params.xxx(Vue2)或route.params.xxx(Vue3),但一定要记住刷新会丢数据!比如你传了个msg参数,页面第一次打开能拿到,但刷新后route.params.msg就变成undefined了,因为URL里没存这个参数,路由匹配时“不认”它。

params和query参数有啥本质区别?

很多人学的时候会把params和query搞混,其实它们在传参方式、URL表现、刷新保留逻辑上都不一样,得搞清楚什么时候用哪个~

传参方式与URL表现

  • query参数:永远跟在URL的后面,像/user?name=张三&age=18,很像HTTP GET请求的查询参数,不管路由规则咋写,query都会明明白白显示在URL里。

  • params参数:分两种情况:

    • 动态路由传参时,params是URL路径的一部分(比如/product/123里的123);
    • 命名路由传参且路由无动态段时,params不会显示在URL里(比如跳转到/about时传params,URL还是/about,参数藏在路由对象里)。

刷新后的数据保留

  • query参数:因为写在URL里,刷新页面后数据还在(浏览器会记住URL里的查询串)。

  • params参数:

    • 动态路由传参的params:因为在URL路径里,刷新后也能保留;
    • 命名路由传参且路由无动态段的params:刷新后直接丢失(因为URL没存,路由匹配时找不到这些参数)。

路由匹配规则

  • query参数:不影响路由匹配,比如/user?name=张三/user?name=李四,只要路由规则是path: '/user',都会匹配到User组件。

  • params参数(动态路由里的):直接影响路由匹配,比如路由规则是/user/:userId,那只有访问/user/123/user/456这种带userId的路径才会匹配,要是访问/user(没带userId),就会匹配失败(要么404,要么跳转到其他路由,看你配置的重定向)。

动态路由里的params有啥特殊逻辑?

动态路由(就是路由规则里带:xxx的情况)下,params有个很容易踩的点:组件复用导致数据不更新

举个例子:你做了个商品详情页,路由是/product/:productId,从/product/1跳转到/product/2时,Vue为了性能,会复用Product组件(因为路由path都是/product/:productId,只是params变化),这时候组件的createdmounted等生命周期钩子不会重新执行,所以如果你的数据请求写在created里,页面就会一直显示第一个商品的数据,不会更新。

怎么解决?得监听路由参数的变化

  • Vue2里,用watch监听$route

    export default {
    watch: {
      '$route'(to, from) {
        // to是新路由对象,from是旧的
        this.fetchData(to.params.productId) // 重新请求新商品的数据
      }
    },
    methods: {
      fetchData(productId) { ... }
    }
    }
  • Vue3里,用watch监听useRoute拿到的路由对象:

    import { watch } from 'vue'
    import { useRoute } from 'vue - router'
    export default {
    setup() {
      const route = useRoute()
      watch(route, (newRoute) => {
        fetchData(newRoute.params.productId)
      })
      return {}
    }
    }

传params时最容易踩的3个坑,怎么避?

新手学params,这三个坑几乎人人都踩过,提前避坑能省好多debug时间~

坑:路由没配动态段,传了params,刷新数据丢了

场景:你想给About页面传个消息,用了命名路由+params:

this.$router.push({ name: 'About', params: { msg: 'hello' } })

路由规则里path: '/about'没写动态段,页面第一次打开能拿到msg,但刷新后msg没了。

原因:params没被写进URL,刷新时路由重新匹配,系统“不认识”这些参数,自然就丢了。

解决

  • 如果你需要刷新后参数还在,要么把参数加到路由的动态段里(改成path: '/about/:msg',但这种情况适合参数是页面必需的,比如标识页面状态);
  • 要么改用query传参(this.$router.push({ path: '/about', query: { msg: 'hello' } })),query会显示在URL里,刷新也能保留。

坑:动态路由跳转后,组件没更新(数据还是旧的)

场景:商品详情页从/product/1跳转到/product/2,页面还是显示商品1的信息。

原因:路由path相同(都是/product/:productId),Vue复用了Product组件,生命周期钩子不重新执行,所以数据没更新。

解决:像前面说的,用watch监听$route(Vue2)或route(Vue3)的变化,参数变了就重新请求数据。

坑:用path跳转时传params,参数没生效

场景:你想传params,却用了path字符串+params对象的写法:

this.$router.push({ 
  path: '/user', 
  params: { userId: 123 } 
})

结果页面里拿$route.params.userIdundefined

原因:vue - router的规则是——用path跳转时,params会被直接忽略!因为path和params是“两套系统”,只有用name+params,或者动态拼接path(如/user/${userId}),params才会生效。

解决:跳转时二选一:

  • name+paramsthis.$router.push({ name: 'User', params: { userId: 123 } })(前提是路由配置了name: 'User');
  • 动态拼接path:this.$router.push(/user/${this.userId}。

实战场景:什么时候该用params?

params不是万能的,但在这些场景下,用它比query更合适~

页面层级深,参数属于资源唯一标识(适合动态路由)

比如电商的商品详情、用户个人主页、订单详情页,这些页面的ID是资源的唯一标识,把ID放在路由path里(如/product/:id)更语义化,用户分享链接时别人也能直接访问对应的资源;对SEO也友好,搜索引擎能通过URL里的ID识别不同页面。

参数敏感,不想暴露在URL查询串(但要注意命名路由传参的局限性)

有些场景下,参数不太适合明晃晃地显示在URL里(比如临时的用户操作标记、内部状态),这时候可以用命名路由+params传参(路由无动态段的情况),虽然刷新会丢,但胜在URL干净,比如从商品列表页跳转到详情页时,传一个“是否自动展开评论区”的标记,页面内用一下,刷新后重置状态也合理。

配合路由元信息(meta)做权限控制时传参

有时候需要根据params里的参数判断页面权限,比如后台管理系统里,不同角色(admin、editor)能访问的页面不同,路由配置成path: '/admin/:role',然后在导航守卫beforeEnter里判断:

{
  path: '/admin/:role',
  name: 'Admin',
  component: Admin,
  beforeEnter: (to, from, next) => {
    if (to.params.role === 'admin') {
      next() // 管理员可以进
    } else {
      next('/403') // 其他角色跳权限不足页
    }
  }
}

这种情况下,params作为路由的一部分,能在守卫里直接拿到,方便做权限逻辑。

Vue3中用params有啥新变化?(配合Composition API)

Vue3里,使用useRouteuseRouter来替代this.$routethis.$router,比如接收params:

import { useRoute } from 'vue - router'  
const route = useRoute()  
const productId = route.params.productId  

跳转传参:

import { useRouter } from 'vue - router'  
const router = useRouter()  
// 动态路由拼接  
router.push(`/product/${productId}`)  
// 命名路由+params  
router.push({ name: 'Product', params: { productId: 123 } })  

在setup里监听路由变化,需要用watch

import { watch } from 'vue'  
import { useRoute } from 'vue - router'  
const route = useRoute()  
watch(route, (newRoute, oldRoute) => {  
  // 当params变化时执行  
  console.log(newRoute.params.productId)  
}, { immediate: true }) // 可选immediate首次加载执行  

这里要讲清楚Composition API的用法和Vue2的区别,帮助升级项目的同学理解。

掌握vue - router的params参数,要理解它和路由规则的绑定关系、传参接收的方式、和query的区别,还要避开那些容易踩的坑,把这些搞明白,不管是做单页应用的路由传参,还是处理复杂的动态路由场景,都能游刃有余啦~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门