不只懂 Vue 语法:如何透过路由实现跨页面传递资料?

问题回答

在跳转页面时,可以透过路由物件里 params 或 query 来传递资料,也可以使用各种不同模式的 Route props 来传递资料。前者需要依赖 URL ,例如 params 需要依靠动态路由,即是/example/:id 来完成。query 则需要在 URL 里写 /example?id=123 这样的格式来传送。

相反,各种模式的 route props 就比较灵活,不用依赖 URL,而且不用透过 route 物件来取得资料像是 this.$route.params 这样的写法就能省下。因为我们可以直接在页面元件设定 props,直接用意 props 来取得经由路由传递过来的资料。

以下会再作详细解说。

前言

但在进入主题之前,先简单重温在 Vue 有什麽方法实现跨页面资料:

  • eventbus(Vue 2) / mitt(Vue 3)
  • route props (params, query 等等)
  • Vuex

注意,目前讨论的情况是跨页面传资料,不是父子元件之间传资料,因此 props/emit 以及 provide/inject 方法就不适用於此情况。

回到重点,此文章会集中说明 route props 的方法。

常用的 params 和 query

先说明最简单的 params 和 query 用法。这也是新手刚学 Vue 时最常用到的方法。

先说明 params,做法是在路由设定参数:

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User }
  ]
})

当输入 /user/111 後,可以在 route object 里取得 params:

console.log(this.$route.params.id) 
// 111

第二种是 query,路由直接设定为 /user 即可。但 URL 必须使用这格式:/user?id=111

同样地,使用 route object 取得由以上路由传来的 query,结果会回传一个物件:

console.log(this.$route.query) 
// {id: '111'}

使用 $router.push时,只能择一填写 paramspath 属性

另外提醒,当使用 $router.push() 的方法来跳转页面时,要注意:

正确写法:

const id = '123'
this.$router.push({ 
    name: 'user', // 要事先在 router 那边命名你的元件
    params: { id } 
})

或者

this.$router.push({ path: `/user/${id}` })

错误写法:

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

然而,传 query 的话就没有此限制:

this.$router.push({
    path: '/user',
    query: { id }
})

params 与 query 的分别

1. params 可以不显示在 URL 里

query 所传送的参数会显示在 URL 里,但 params 则不一定。像以下写法:

const id = "111";
this.$router.push({
    name: 'User', // 即是 /user 
    params: { id }
});

结果会跳转到 /user 此 URL,在 URL 里不会显示 id 的值。反之,使用 query 的话,参数一定会显示在 URL 里。

2. 重刷页面後会失去 params 资料,但 query 资料仍存在

很重要一点,重刷页面时,如果使用 query 传参,资料仍然会存在。反之,params 传参的话,资料就会消失。

如何传物件资料,或多笔资料?

说到重点了,如果我要跨页面传多笔资料,或者是物件资料。如何使用路由传参的方法来完成?

传送多个值

如果要传送多个值,使用 paramsquery 也可。

前者的话,只要在$router.push()里的 params 物件里再塞资料就可以:

this.$router.push({
    name: 'User',
    params: { 
        id: 111, // 注意,传送後会转为字串
        name: 'Alysa'
    }
});

query 的做法:

this.$router.push("/user?id=111&name=Alysa")

this.$router.push({
    path: '/user',
    query: { 
        id: 111, // 注意,传送後会转为字串 
        name: 'Alysa'
    }
})

传送资料型别会变成字串

然而,以上示范可见,params 和 query 所传送的值都会变为字串型别。因此如果值是物件的话,就没法传送。不然会变成 "[object Object]"。这情况下,如果透过 params 来传资料就会有问题。解决方法会用 JSON.parseJSON.stringify 来转换资料。

不需要依靠 route 来传递资料

以上示范,我们要用 $route.params 这些方法取得 params 和 query。但如果使用 route props 的各种传送 route props 的模式,就可以更灵活,不再使用 $router 来取得资料也行!

Boolean mode

布林模式,需要设定动态路由以及 props: true

以下例子,假设我要把 id 资料,由某一页传到 A 元件页面里使用。

router/index.js

const routes = [
  {
    path: "/",
    component: Home
  },
  {
    path: "/a/:id",
    name: "a",
    component: A,
    props: true
  }
];

A 元件

<template>
  <h1>这是 A 页面</h1>
  <p>以下是从首页传来的资料:</p>
  <p>{{ id }}</p>
</template>
<script>
export default {
  props: {
    id: {
      type: String,
    },
  },
};
</script>

不用再透过 this.$route.params 来取资料了!直接在元件里的 props 接收 id 资料,并显示出来。但注意,元件所接收的 props,只能是 params。

Function mode

在路由物件里,建立一个函式来回传 props,给页面元件使用。
跟 Boolean mode 明显不同:

  • 不用写动态路由
  • 可以传 params 或 query
  • 更方便传送物件或阵列资料

以下先示范传 params 做法。假设我要做以下的事:

  • 在首页打 API,取得 random user API 回传的资料
  • 由首页跳转到名为 Bparams 的页面元件
  • Bparams 页面元件要接收到在首页打 API 取得的资料

router/index.js

{
    path: "/b-params",
    name: "Bparams",
    component: Bparams,
    props: (route) => route.params
}

Home.vue(首页)
按按钮後,就跳转到 Bparams页面,并把 API 回传资料用 params 传出去。

<template>
    <h2>Function mode(传 params)</h2>
    <p>按按钮後打 API,用 function mode,把 API 资料传到 B-params 页面</p>
    <a href="#" @click.prevent="passDataToB">去 B-params 页面</a>
</template>
export default {
  methods: {
    passDataToB() {
      fetch("https://randomuser.me/api/")
        .then((res) => res.json())
        .then((res) => {
          this.$router.push({
            name: "Bparams",
            params: {
              ...res.results[0],
            },
          });
        })
        .catch((err) => console.log(err));
    },
  },
};

Bparams.vue

<template>
  <h1>这是 B 页面</h1>
  <p>以下是从首页传来的资料:</p>
  <p>{{ user }}</p>
</template>
export default {
  props: {
    user: {
      type: Object,
    },
  },
};

Object mode

物件模式适用於传入静态资料。直接在 props 物件里定义要传送的资料即可。
以下示范把资料传入 C 页面元件:

router/index.js

{
    path: "/c",
    name: "c",
    component: C,
    // Object mode
    props: {
      userStatic: {
        username: "Tom",
        age: 20
      }
    }
}

C.vue

<template>
    <h1>这是 C 页面</h1>
    <p>以下是从 router props 传来的静态资料:</p>
    <p>{{ userStatic }}</p>
</template>
export default {
  props: {
    userStatic: {
      type: Object,
    },
  },
};

示范所有模式的程序码

https://codesandbox.io/s/router-props-function-mode-ktzbr?file=/src/views/Home.vue

总结

  • 透过路由实现跨页面传递资料,可分为两种方法,一是依赖 URL 来使用 params 或 query。二是使用各种模式的 route props 来传资料。
  • 当使用 this.$router.push() 来跳转页面时,如果是传 params,要注意 path 和 params 属性不能共存,只能择一填写。
  • 传 params 时,值会变为字串型别。
  • 使用 route props 会比一般依赖使用 URL 来传 params 和 query 更灵活。

参考资料

How to pass Vue Router params as props to components
【Vue.js】Vue Router 之透过路由组件传参数给元件


<<:  Day07 X Image Sprites

>>:  Day-08 Android专案架构

输出的重要性

在去年参加 iT 铁人赛挑战时,选择的题目是需要实作(见:30 天开发 Android App 的流...

[day21]Vue实作-登出及会员功能实作

登出模式及未登入限制读取页面 navbar.vue调整 登出登入的切换调整 利用v-show来判断是...

铁人赛 Day7 -- 一定要知道的 CSS (四) -Justify-content

前言 昨天讲了 display 当中的 Flex 属性 那今天就要来讲 display 当中的 Ju...

【第二九天 - Flutter 开发套件之旅(下)】

前言 我们在前一天开发完成了套件,那麽就试着来上架ㄅ 。 可以查看 官方文件,肯定讲的比我清楚哈哈(...

资料分析商业应用与策略管理 #笔记二

数位化时代里,不管我们正在做什麽、想要做什麽,过程中都在产生资料,可以说每个人是巨量资料的发展历程,...