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

Vue Router 怎么处理多个参数?从配置到传参再到页面使用全解析

terry 5小时前 阅读数 11 #Vue

在Vue项目开发中,经常会碰到需要给路由传递多个参数的情况,像电商详情页要同时传商品ID和分类ID、后台管理列表要带搜索关键词和分页信息这些场景,很多刚接触Vue Router的小伙伴会犯愁:“Vue Router 怎么处理多个参数?” 这篇文章从路由配置、传参方法、参数获取,到实战场景和避坑技巧,把多个参数的玩法拆解得明明白白,新手也能跟着一步步搞懂~

路由里多个参数的配置逻辑

要让路由能接收多个参数,得先搞清楚两种常见配置思路:动态路由参数(动态段)查询参数(query)

动态路由参数配置

动态段是路由 path 里用 开头的占位符,用来匹配 URL 里的动态部分,比如做商品详情页,需要同时传商品 ID 和分类 ID,路由可以这么配:

const routes = [
  {
    path: '/product/:productId/:categoryId',
    name: 'ProductDetail',
    component: ProductDetail
  }
]

这里 productIdcategoryId 是动态段,当用户访问 /product/123/456 时,Vue Router 会把 123456 分别对应到 productIdcategoryId,存到 $route.params 里。

这种配置的特点是 参数是 URL 路径的一部分:用户分享链接时参数不会丢,且这些参数是访问页面的“必要条件”——少一个参数,页面可能无法正常渲染(比如商品 ID 丢了,就查不到对应商品数据)。

查询参数配置

查询参数不用改路由的 path,而是通过 后面的键值对传递,适合传“可选参数”,比如后台订单列表的搜索页,需要关键词、分页、状态等筛选条件,路由可以这么配:

const routes = [
  {
    path: '/admin/order',
    name: 'OrderList',
    component: OrderList
  }
]

访问时 URL 是 /admin/order?keyword=手机&page=2&status=待发货,这些 keywordpagestatus 就是查询参数,存到 $route.query 里。

查询参数的优势是 灵活可选:页面能根据有无参数做不同逻辑,刷新后参数也会保留,但它们不是 URL 路径的“必须部分”——就算不传,页面也能打开(比如默认展示第一页、所有状态的订单)。

动态段适合传“必要且固定在路径里”的参数,查询参数适合传“可选且拼接在路径后”的参数,实际项目里常结合两种方式:比如商品详情页用动态段传商品 ID 和分类 ID,再用查询参数传“是否显示推荐”这类可选配置。

给路由传多个参数的不同方式

知道了怎么配置路由,接下来得搞清楚怎么往路由里传多个参数,Vue Router 提供了好几种传参方式,不同场景选不同方式更顺手~

动态路由传参(配合动态段)

如果路由里配了动态段(比如前面的 /product/:productId/:categoryId),传参时要把参数拼到 URL 里,有两种常用写法:

  • <router-link> 组件传参:用模板字符串把参数拼起来

    <router-link :to="`/product/${productId}/${categoryId}`">
    查看商品详情
    </router-link>

    这里 productIdcategoryId 是组件里的变量,点击后 URL 会变成 /product/实际ID/实际分类ID,参数会被解析到 $route.params 里。

  • 编程式导航传参:用 this.$router.push 拼接路径

    this.$router.push(`/product/${this.productId}/${this.categoryId}`)

    这种方式和 <router-link> 原理一样,适合在点击按钮、接口回调等逻辑里触发路由跳转。

动态路由传参的特点是 参数强制可见——必须把参数拼到 URL 里才能访问对应页面,适合“没参数就开不了页”的场景(比如商品详情页没商品 ID 就查不到数据)。

查询参数(query)传参

查询参数传参不需要改路由的 path,而是把参数放到 query 对象里,同样分 <router-link> 和编程式导航两种写法:

  • <router-link> 传 query:通过 to 的对象语法传

    <router-link 
    :to="{ 
      path: '/search', 
      query: { keyword: searchKeyword, page: currentPage } 
    }"
    >
    搜索
    </router-link>

    这里 searchKeywordcurrentPage 是组件内的变量,点击后 URL 会变成 /search?keyword=xxx&page=xx,参数存在 $route.query 里。

  • 编程式导航传 query:用 push 的对象语法

    this.$router.push({
    path: '/search',
    query: { keyword: this.searchKeyword, page: this.currentPage }
    })

查询参数的优势是 灵活可缺省:就算不传某个参数,页面也能正常打开(比如默认 page=1),而且多个参数可以自由组合,适合筛选、分页这类“多条件可选”的场景。

命名路由结合 params 传参

如果路由配了 namename: 'ProductDetail'),还可以用 params 对象传参,但要注意:params 传参时,必须配合 name,不能用 path(因为 pathparams 一起用会被 Vue Router 忽略),写法如下:

  • <router-link> 传 params

    <router-link 
    :to="{ 
      name: 'ProductDetail', 
      params: { productId: productId, categoryId: categoryId } 
    }"
    >
    查看商品详情
    </router-link>
  • 编程式导航传 params

    this.$router.push({
    name: 'ProductDetail',
    params: { productId: this.productId, categoryId: this.categoryId }
    })

这种方式的参数会不会显示在 URL 里?要看路由有没有配动态段:

  • 如果路由 path/product/:productId/:categoryIdparams 里的参数会被解析到 URL 路径中;
  • 如果路由 path/product(没配动态段),params 里的参数不会显示在 URL 里,且刷新页面后参数会丢失

所以这种方式更适合“参数必须在 URL 里体现,且路由已经配好动态段”的场景,相当于动态路由传参的“命名路由版”。

页面中怎么获取多个路由参数

路由把参数传过来了,页面组件里怎么拿到这些参数?关键是要熟悉 $route 对象里的 paramsquery

动态路由参数:$route.params

动态路由的参数存在 this.$route.params 里,直接取对应的键就行,比如在 ProductDetail 组件里:

<template>
  <div>
    <h1>当前商品ID:{{ productId }}</h1>
    <h2>所属分类ID:{{ categoryId }}</h2>
  </div>
</template>
<script>
export default {
  data() {
    return {
      productId: '',
      categoryId: ''
    }
  },
  created() {
    // 组件创建时,从 $route.params 拿参数
    this.productId = this.$route.params.productId
    this.categoryId = this.$route.params.categoryId
    // 拿到参数后请求商品数据
    this.fetchProduct()
  },
  methods: {
    fetchProduct() {
      // 用 productId 和 categoryId 发请求,
      // axios.get(`/api/product/${this.productId}?category=${this.categoryId}`)
    }
  }
}
</script>

但这里有个坑:如果路由参数变化了,但组件没被销毁(比如从 /product/1/2 跳到 /product/3/2,组件还是 ProductDetail),created 钩子不会再执行,这时候参数更新了,页面数据却没变化,怎么解决?

  • watch 监听 $route 的变化:

    watch: {
    '$route'(to) {
      // to 是新的路由对象,from 是旧的(可省略)
      this.productId = to.params.productId
      this.categoryId = to.params.categoryId
      this.fetchProduct() // 重新请求数据
    }
    }
  • 或者用 Vue Router 提供的 beforeRouteUpdate 导航守卫:

    beforeRouteUpdate(to, from, next) {
    this.productId = to.params.productId
    this.categoryId = to.params.categoryId
    this.fetchProduct()
    next() // 必须调用 next() 才能继续导航
    }

查询参数:$route.query

查询参数存在 this.$route.query 里,获取方式和 params 类似,比如在 SearchPage 组件里处理搜索关键词和分页:

<template>
  <div>
    <input v-model="keyword" placeholder="请输入关键词" />
    <button @click="handleSearch">搜索</button>
    <div>当前页码:{{ page }}</div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      keyword: '',
      page: 1
    }
  },
  created() {
    // 从 query 里拿初始参数(比如页面刷新后,保留之前的搜索条件)
    this.keyword = this.$route.query.keyword || ''
    this.page = this.$route.query.page || 1
  },
  watch: {
    '$route'(to) {
      // 路由变化时(比如用户点击分页按钮,路由 query 变化)
      this.keyword = to.query.keyword || ''
      this.page = to.query.page || 1
      this.fetchSearchResult()
    }
  },
  methods: {
    handleSearch() {
      this.$router.push({
        path: '/search',
        query: { keyword: this.keyword, page: this.page }
      })
    },
    fetchSearchResult() {
      // 根据 keyword 和 page 发请求,
      // axios.get(`/api/search?keyword=${this.keyword}&page=${this.page}`)
    }
  }
}
</script>

查询参数同样要注意“组件复用导致数据不更新”的问题,所以也要用 watch 或导航守卫来处理参数变化。

用计算属性或侦听器简化代码

如果组件里要频繁用 $route.params$route.query,可以用计算属性把参数“封装”一下,让模板更简洁。

<template>
  <div>
    <h1>商品ID:{{ productId }}</h1>
    <h2>分类ID:{{ categoryId }}</h2>
  </div>
</template>
<script>
export default {
  computed: {
    productId() {
      return this.$route.params.productId
    },
    categoryId() {
      return this.$route.params.categoryId
    }
  },
  created() {
    this.fetchProduct()
  },
  watch: {
    productId() {
      this.fetchProduct()
    },
    categoryId() {
      this.fetchProduct()
    }
  },
  methods: {
    fetchProduct() {
      // 发请求逻辑
    }
  }
}
</script>

这样模板里直接用 productIdcategoryId,不用每次都写 this.$route.params.xxx,代码更干净~

多参数路由的实战场景举例

光讲理论不够直观,结合实际项目场景看看多参数路由怎么用~

电商商品详情页(动态路由多参数)

需求:用户点商品卡片进入详情页,需要展示商品信息和所属分类下的推荐商品,这时候商品 ID 和分类 ID 都是必要参数,必须放在 URL 路径里,所以用动态路由。

  • 路由配置

    {
    path: '/product/:productId/:categoryId',
    name: 'ProductDetail',
    component: ProductDetail
    }
  • 传参(以编程式导航为例):
    用户点商品卡片时,触发方法:

    handleProductClick(productId, categoryId) {
    this.$router.push(`/product/${productId}/${categoryId}`)
    }
  • 组件内获取参数并请求数据

    <template>
    <div>
      <div v-if="loading">加载中...</div>
      <div v-else>
        <h1>{{ productInfo.title }}</h1>
        <p>{{ productInfo.desc }}</p>
        <h2>同分类推荐</h2>
        <ul>
          <li v-for="item in relatedProducts" :key="item.id">{{ item.title }}</li>
        </ul>
      </div>
    </div>
    </template>
    <script>
    import axios from 'axios'
    export default {
    data() {
      return {
        loading: true,
        productInfo: {},
        relatedProducts: []
      }
    },
    created() {
      this.fetchData()
    },
    watch: {
      '$route'() {
        this.fetchData()
      }
    },
    methods: {
      async fetchData() {
        this.loading = true
        const { productId, categoryId } = this.$route.params
        // 请求商品详情
        const productRes = await axios.get(`/api/product/${productId}`)
        // 请求同分类推荐商品
        const relatedRes = await axios.get(`/api/category/${categoryId}/products`)
        this.productInfo = productRes.data
        this.relatedProducts = relatedRes.data
        this.loading = false
      }
    }
    }
    </script>

这里用动态路由把必要参数放 URL 里,既保证了页面分享的完整性,又让 SEO 更友好(搜索引擎能抓取到不同商品页的 URL)。

后台管理系统的订单列表(查询参数多参数)

需求:订单列表需要支持关键词搜索、分页、状态筛选,而且刷新页面后筛选条件要保留,这时候筛选条件是可选的,适合用查询参数。

  • 路由配置

    {
    path: '/admin/order',
    name: 'OrderList',
    component: OrderList
    }
  • 传参(以 <router-link> 为例,假设当前页是第 2 页,搜索关键词是“手机”,状态是“待发货”):

    <router-link 
    :to="{ 
      path: '/admin/order', 
      query: { keyword: '手机', page: 2, status: '待发货' } 
    }"
    >
    查看筛选后的订单
    </router-link>
  • 组件内获取参数并请求数据

    <template>
    <div>
      <input v-model="keyword" placeholder="搜索关键词" />
      <select v-model="status">
        <option value="">全部状态</option>
        <option value="待支付">待支付</option>
        <option value="待发货">待发货</option>
      </select>
      <button @click="handleFilter">筛选</button>
      <div class="pagination">
        <button @click="handlePageChange(1)">第1页</button>
        <button @click="handlePageChange(2)">第2页</button>
      </div>
      <table>
        <tr v-for="order in orderList" :key="order.id">
          <td>{{ order.id }}</td>
          <td>{{ order.name }}</td>
          <td>{{ order.status }}</td>
        </tr>
      </table>
    </div>
    </template>
    <script>
    import axios from 'axios'
    export default {
    data() {
      return {
        keyword: '',
        status: '',
        page: 1,
        orderList: []
      }
    },
    created() {
      // 从 query 里拿初始参数
      this.keyword = this.$route.query.keyword || ''
      this.status = this.$route.query.status || ''
      this.page = this.$route.query.page || 1
      this.fetchOrders()
    },
    watch: {
      '$route'() {
        // 路由变化时(比如用户点分页按钮,query 变化)
        this.keyword = this.$route.query.keyword || ''
        this.status = this.$route.query.status || ''
        this.page = this.$route.query.page || 1
        this.fetchOrders()
      }
    },
    methods

版权声明

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

发表评论:

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

热门