Vue Router

安装

1
npm install vue-router

基本使用

创建路由实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { createRouter, createWebHistory } from 'vue-router';

import HomeView from '@/views/HomeView.vue';
import AboutView from '@/views/AboutView.vue';

// 配置路由
const routes = [
  { path: '/', component: HomeView },
  { path: '/about', component: AboutView },
];

// 创建路由实例
const router = createRouter({
  history: createWebHistory(), // HTML5模式
  routes, // 路由配置
});

export default router;

注册路由插件

1
2
3
4
5
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

createApp(App).use(router).mount('#app'); // use() 需要在 mount() 之前调用

插件的功能有:

  • 全局注册 RouterView 和 RouterLink 组件。
  • 添加全局 $router 和 $route 属性。
  • 启用 useRouter() 和 useRoute() 组合式函数。
  • 触发路由器解析初始路由。

使用路由

1
2
3
4
5
6
7
8
9
10
11
12
<template>
  <p><strong>当前路由路径为</strong> {{ $route.fullPath }}</p>
  <!-- 导航区 -->
  <nav>
    <router-link to="/">Go to Home</router-link>
    <router-link to="/about">Go to About</router-link>
  </nav>
  <!-- 主体区 -->
  <main>
    <router-view />
  </main>
</template>

使用 router-link 组件创建链接,使得 Vue Router 能够在不重新加载页面的情况下改变 URL,处理 URL 的生成、编码和其他功能。

RouterView 组件可以使 Vue Router 知道你想要在哪里渲染当前 URL 路径对应的路由组件。它需要在某处被导入,否则 Vue Router 就不会渲染任何东西。

注意

  1. 路由组件通常存放在 pages 或 views 文件夹,一般组件通常存放在 components 文件夹。
  2. 通过点击导航,视觉效果上“消失” 了的路由组件,默认是被卸载掉的,需要的时候再去挂载。

不同的历史模式

在创建路由器实例时,history 配置允许我们在不同的历史模式中进行选择。

Hash 模式

  • 优点:兼容性更好,因为不需要服务器端处理路径。
  • 缺点:URL 带有 # 不太美观,且在 SEO 优化方面相对较差。如:https://example.com/#/user/id
1
2
3
4
5
6
7
8
import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    //...
  ],
})

HTML5 模式

  • 优点:URL 更加美观,不带有 #,更接近传统的网站 URL。如:https://example.com/user/id
  • 缺点:后期项目上线,需要服务端配合处理路径问题,否则刷新会有404错误。
1
2
3
4
5
6
7
8
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    //...
  ],
})

to的两种写法

1
2
3
4
5
<!-- 第一种:to的字符串写法 -->
<router-link active-class="active" to="/home">主页</router-link>

<!-- 第二种:to的对象写法 -->
<router-link active-class="active" :to="{path:'/home'}">Home</router-link>

嵌套路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export default createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/users/:username',
      component: User,
      children: [
        { path: '', component: UserHome }, // User 组件的默认子路由
        { path: 'profile', component: UserProfile },
        { path: 'posts', component: UserPosts },
      ],
    },
  ],
});

注意,以 / 开头的嵌套路径将被视为根路径。嵌套的子路由不能 / 开头

命名路由

当创建一个路由时,可以选择给路由一个 name:

1
2
3
4
5
6
7
const routes = [
  {
    path: '/user/:username',
    name: 'profile',
    component: User
  }
]

然后可以使用 name 而不是 path 来传递 to 属性给 <router-link>:

1
2
3
<router-link :to="{ name: 'profile', params: { username: 'xiaowhang' } }">
  User profile
</router-link>

优点

  • 没有硬编码的 URL。
  • params 的自动编码/解码。
  • 防止你在 URL 中出现打字错误。
  • 绕过路径排序,例如展示一个匹配相同路径但排序较低的路由。

注意

所有路由的命名都必须是唯一的。如果为多条路由添加相同的命名,路由器只会保留最后那一条。

路由组件传参

query参数

传递参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 跳转并携带query参数(to的字符串写法) -->
<router-link to="/users?id=xiaowhang&b=2">跳转</router-link>

<!-- 跳转并携带query参数(to的对象写法) -->
<router-link
  :to="{
    // name:'user', // 用name也可以跳转
    path: '/users',
    query: { id: 'xiaowhang', b: 2 },
  }"
>
  跳转
</router-link>

接收参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
  <div>{{ $route.query }}</div>
</template>

<!-- 或者 -->

<template>
  <div>{{ route.query }}</div>
</template>

<script setup>
  import { useRoute } from 'vue-router';
  const route = useRoute();
</script>

params参数

传递参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--
    routes: [{
      path: '/users/:username/:b',
      component: User,
      },
    ],
-->

<!-- 跳转并携带params参数(to的字符串写法) -->
<router-link to="/users/xiaowhang/2">跳转</router-link>

<!-- 跳转并携带params参数(to的对象写法) -->
<router-link
  :to="{
    name:'user',
    params: { id: 'xiaowhang', b: 2 },
  }"
>
  跳转
</router-link>

接收参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
  <div>{{ $route.params }}</div>
</template>

<!-- 或者 -->

<template>
  <div>{{ route.params }}</div>
</template>

<script setup>
  import { useRoute } from 'vue-router';
  const route = useRoute();
</script>

注意

  1. 传递 params 参数时,若使用to的对象写法,必须使用name配置项,不能用path。
  2. 传递 params 参数时,需要提前在规则中占位。

将 props 传递给路由组件

作用:让路由组件更方便的收到参数(可以将路由参数作为props传给组件)

1
2
3
4
5
6
7
8
9
10
11
12
13
{
  name: 'user',
  path: '/users/:id/:b',
  component: User,
  // 布尔模式,作用:把收到了每一组params参数,作为props传给Detail组件
  props: true,

  // 对象模式,作用:把对象中的每一组key-value作为props传给Detail组件
  // props: { id: xiaowhang, b: 2, c: 3 },

  // 函数模式,作用:把返回的对象中每一组key-value作为props传给Detail组件
  // props: route => route.query,
},
1
2
3
4
5
6
7
8
<template>
  <div>{{ id }}</div>
  <div>{{ b }}</div>
</template>

<script setup>
  defineProps(['id', 'b']);
</script>

replace属性

  1. 作用:控制路由跳转时操作浏览器历史记录的模式。

  2. 浏览器的历史记录有两种写入方式:分别为 push 和 replace:

    • push 是追加历史记录(默认值)。
    • replace 是替换当前记录。
  3. 开启replace模式:

    1
    <router-link :to="..." replace>News</router-link>

编程式导航

1
2
3
4
import { useRoute, useRouter } from 'vue-router';

const route = useRoute(); // 获取当前路由信息
const router = useRouter(); // 获取路由实例

导航到不同的位置

声明式编程式
<router-link :to="...">...</router-link>router.push(...)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 字符串路径
router.push('/users/xiaowhang')

// 带有路径的对象
router.push({ path: '/users/xiaowhang' })

// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'xiaowhang' } })

// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })

// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })

const username = 'xiaowhang'

// 我们可以手动建立 url,但我们必须自己处理编码
router.push(`/user/${username}`) // -> /user/xiaowhang

// 同样
router.push({ path: `/user/${username}` }) // -> /user/xiaowhang

// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益
router.push({ name: 'user', params: { username } }) // -> /user/xiaowhang

// `params` 不能与 `path` 一起使用
router.push({ path: '/user', params: { username } }) // -> /user

替换当前位置

声明式编程式
<router-link :to="..." replace>...</router-link>router.replace(...)

也可以直接在传递给 router.push 的 to 参数中增加一个属性 replace: true :

1
2
3
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })

横跨历史

1
2
3
4
5
6
7
8
9
10
11
12
// 向前移动一条记录,与 router.forward() 相同
router.go(1)

// 返回一条记录,与 router.back() 相同
router.go(-1)

// 前进 3 条记录
router.go(3)

// 如果没有那么多记录,静默失败
router.go(-100)
router.go(100)

重定向

作用:将特定的路径,重新定向到已有路由。

从 / 重定向到 /home :

1
const routes = [{ path: '/', redirect: '/home' }]

重定向的目标也可以是一个命名的路由:

1
const routes = [{ path: '/', redirect: { name: 'homepage' } }]

也可以是一个方法,动态返回重定向目标:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const routes = [
  {
    // /search/screens -> /search?q=screens
    path: '/search/:searchText',
    redirect: to => {
      // 方法接收目标路由作为参数
      // return 重定向的字符串路径/路径对象
      return { path: '/search', query: { q: to.params.searchText } }
    },
  },
  {
    path: '/search',
    // ...
  },
]

相对重定向

1
2
3
4
5
6
7
8
9
10
11
12
const routes = [
  {
    // 将总是把/users/123/posts重定向到/users/123/profile。
    path: '/users/:id/posts',
    redirect: to => {
      // 该函数接收目标路由作为参数
      // 相对位置不以`/`开头
      // 或 { path: 'profile'}
      return 'profile'
    },
  },
]

命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图。

1
2
3
4
<template>
  <router-view class="view sidebar" name="Sidebar" />
  <router-view class="view main-content" />
</template>

一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export default createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      components: {
        // 它们与 `<router-view>` 上的 `name` 属性匹配
        default: Home,
        // Sidebar: Sidebar 的缩写
        Sidebar,
      },
    },
  ],
});

Vue Router
http://xiaowhang.github.io/archives/1237244176/
作者
Xiaowhang
发布于
2024年10月15日
许可协议