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() 之前调用

插件的功能有:

  • 全局注册 RouterViewRouterLink 组件。
  • 添加全局 $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. 路由组件通常存放在 pagesviews 文件夹,一般组件通常存放在 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. 浏览器的历史记录有两种写入方式:分别为 pushreplace

    • 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.pushto 参数中增加一个属性 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日
许可协议