Vue-Router 笔记 
目录
快速部署(TS) 
// @/router/index.ts
// 导入页面
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
// 配置路由
const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes: [
        {
            path: '/',
            name: 'home',
            alias: '/home',
            component: HomeView
        },
        {
            // 页面路径
            path: "/square",
            // 页面名
            name: "square",
            // 对于的vue代码,这样写页面会在打开时才加载
            component: () => import('@/views/square.vue')
        },
        {
            path: "/knowledgebase/:id*",
            name: "knowledgebase",
            component: () => import('@/views/KnowledgeBaseView.vue')
        },
        {
            path: "/content/:id",
            name: "new",
            component: () => import('@/views/ContentView.vue')
        },
        {
            // 匹配其他漏掉的页面
            path: "/:pathMatch(.*)*",
            name: "404",
            component: () => import('@/views/404View.vue')
        }
    ]
})
// 路由守卫
router.afterEach((to, from) => {
    const hash = to.hash
    if (hash) {
        const targetElement = document.getElementById(hash.substring(1));
        if (targetElement) {
            targetElement.scrollIntoView();
        }
    }
})
// 导出路由
export default router使用
// @/main.ts
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
const app = createApp(App);
app.use(router);
app.mount("#app");// @/App.vue
<template>
  <!-- 使用路由 -->
  <router-view></router-view>
</template>
// xxx.vue
<template>
  <!-- 跳转到对应组件 -->
  <router-link to="/home">home</router-link>
</template>配置 Vue-Router
import components | 导入路由组件 
2 种导入方法
// 首页加载时就会加载页面(不管首页是不是它)
import HomeView from '../views/HomeView.vue'
// 只有访问了对应的路径才会加载页面,可以加快首页的加载速度
{
    path: '/',
    name: 'home',
    alias: '/home',
    component: () => import('@/views/HomeView.vue')
}
// 补充一种奇怪的东西
// 路由组件对象只需要有component属性就行(怪)
const User = {
  template: '<div>User</div>',
}
const routes = [
  { path: '/users', component: User },
]createRouter | 路由配置 
import { createRouter } from 'vue-router'
const router = createRouter({
  history: // ...
  routes: [
    //...
  ],
})history | 不同的历史模式 
Hash 模式 
hash 模式是用 createWebHashHistory() 创建的:
import { createRouter, createWebHashHistory } from "vue-router";
const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    //...
  ],
});它在内部传递的实际 URL 之前使用了一个哈希字符(#)。由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。不过,它在 SEO(搜索引擎优化) 中确实有不好的影响。如果你担心这个问题,可以使用 HTML5 模式。
并且使用了这个之后就不能用页面内跳转和跳转到页面指定部分了,因为页面内跳转就是基于这个的
HTML5 模式 
用 createWebHistory() 创建 HTML5 模式,推荐使用这个模式:
import { createRouter, createWebHistory } from "vue-router";
const router = createRouter({
  history: createWebHistory(),
  routes: [
    //...
  ],
});当使用这种历史模式时,URL 会看起来很 "正常",例如 https://example.com/user/id。漂亮!
不过,问题来了。由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置,用户在浏览器中直接访问 https://example.com/user/id,就会得到一个 404 错误。这就尴尬了。
不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。漂亮依旧!
缺点:会增加访问服务器的次数
不同的历史模式 | HTML5 模式 | 服务器配置示例 
不过要注意的是,服务器将不再会报 404 错误,你可以使用复杂的麻烦的配置在服务端实现所有 url 的匹配,然后将其余的返回 404
举例部分:
- NGINX
location / {
  try_files $uri $uri/ /index.html;
}单个页面配置的属性 
const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      // 路径
      path: "/home", // 默认匹配 /home /HomE /home/
      // 路由名称,可以通过路由名称打开路由组件
      name: "home",
      // 路径别名,对应的路径也会打开该路由组件
      alias: "/home",
      // 对应的路由组件
      component: () => import("@/views/HomeView.vue"),
      // 严格检查后缀斜杠,默认false
      strict: true,
      // 严格检查大小写,默认false
      sensitive: true,
    },
  ],
  // 全局使用严格检查
  strict: true,
  sensitive: true,
});动态路由匹配 
静态不讲了,有手就行
const routes = [
  // 普通的匹配
  { path: "/home" },
  // 匹配/home /HomE (不分大小写) /home/
];动态路由匹配用于:
- url 地址是动态的(比如各个用户的主页 url) 
- 需要获取 url 里面的参数 
基础用法
// router/index
const routes = [
  // 动态匹配
  { path: "/users/:username" },
];
// xxxx.vue <js>
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
const router = useRouter();
console.log(route.params);
// 动态路由中匹配到的字符串会解析到这个对象中,字符串数组
// eg:{
// 		user:"truraly"
// }正则复杂用法
const routes = [
  // 动态匹配
  { path: "/users/:username" },
  // 匹配/users/truraly
  // {username:"truraly"}
  { path: "/users/:username/blog/:bid" },
  // 匹配/users/truraly/blog/123
  // {username:"truraly",bid:"123"}
  // /:chapters ->  匹配 /one, /one/two, /one/two/three, 等
  { path: "/:chapters+" },
  // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
  { path: "/:chapters*" },
  // /:chapters -> 匹配 /, /one
  { path: "/:chapters?" },
  // 使用正则规定路径
  { psth: "/users/:uid(\\d+)" }, // 注意双斜杠
  // 匹配/users/114514
  // 只匹配数字,且不能为空
  // { uid: 114514 }
  //
  { path: "/users/:uid(\\d+)*" },
  // 匹配/users /users/123 /users/123/456
  // 匹配多个数字串
  // { uid: [123, 456] }
  //
  { path: "/users/user-:username(\\w+)" },
  // 匹配 /users/user-truraly /users/user-xiabeize
  // { username: "truraly" }
  // 常用于404页面
  { path: "/path404(*)*" },
  // 匹配其他字符串匹配不到的
  // /asda/asd
  // { path404: [ "asda", "asd" ] }
  // 其实这种也能用与404,会有一些区别
  { path: "/path404(*)" },
  // 匹配其他字符串匹配不到的
  // /asda/asd
  // { path404: "asda/asd" }
];使用 vue-router 对加载的影响 
使用 vue 路由时需要注意,跳转页面时相同的组件不会重新加载
比如从一个人的博客跳转到另一个人的博客时,它可能不会按你想象得那样刷新
解决方法:
// plan 1
// xxxx.vue
// 使用watch监视url的变化
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
this.$watch(
  () => route.params,
  (toParams, previousParams) => {
    // 对路由变化做出响应...
  }
);
// plan 2
// router/index.ts
// 使用 beforeRouteUpdate 导航守卫
const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: "/blog/:bid",
      // ...
      async beforeRouteUpdate(to, from) {
        // 对路由变化做出响应...
        let bid = await fetchUser(to.params.bid);
      },
    },
  ],
});children | 嵌套路由 
/user/johnny/profile                  /user/johnny/posts
+------------------+                  +-----------------+
| User             |                  | User            |
| +--------------+ |                  | +-------------+ |
| | Profile      | |  +------------>  | | Posts       | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+在 APP.vue 之外的组件上使用<router-view></router-view>根据 url 的情况选择性加载部分页面
比如用户博客界面和用户信息界面,可以有部分一样的
// 父组件
<div class="user">
	<h2>User {{ $route.params.id }}</h2>
	<router-view></router-view>
</div>// 该父组件的路由配置
{
    path: '/user/:id',
    component: User,
    children: [
        {
            // 当 /user/:id/profile 匹配成功
            // UserProfile 将被渲染到 User 的 <router-view> 内部
            path: 'profile',
            component: UserProfile,
        },
        {
            // 当 /user/:id/posts 匹配成功
            // UserPosts 将被渲染到 User 的 <router-view> 内部
            path: 'posts',
            component: UserPosts,
        },
        {
            // 以/开头的嵌套路径将被视为根路径,即无视父路径匹配/users
            // UserList 将被渲染到 User 的 <router-view> 内部
            path: '/users',
            compenent: UserList
        },
        {
            // 当 /user/:id 匹配成功
            path: '',
            compenent: User-detail
        }
    ]
}- 当子路由被命名时,/user/:id将始终匹配到子路由
const routes = [
  {
    path: "/user/:id",
    component: User,
    // 请注意,只有子路由具有名称
    children: [{ path: "", name: "user", component: UserHome }],
  },
];- 当父子路由都命名时,可以用父路由的名字来导航到父路由(不显示子路由) - 但刷新页面时,会显示嵌套路由,因为这被视为访问了 - url:/user/:id而不是- name:user-parent
const routes = [
  {
    path: "/user/:id",
    name: "user-parent",
    component: User,
    children: [{ path: "", name: "user", component: UserHome }],
  },
];路由的声明式和编程式使用方法 
// 获取RouterLink(声明式)
import { RouterLink } from "vue-router";
// 获取router(编程式)
import { useRouter } from "vue-router";
const router = useRouter();编程式路由底层是对浏览器 windows.history 的一个封装?
差不多
RouterLink 和 router.push()是向 history 栈里添加记录,可以返回
router.replace()是替换栈顶,被替换的网页不能返回
RouterLink | 声明式 
<RouterLink :to="...">
  <!-- 跳转到一个命名路由 -->
  <router-link :to="{ name: 'user', params: { username: 'erina' }}">
    User
  </router-link></RouterLink
>router.push() | 编程式 
// 跳转到对应的url
router.push();
// 字符串路径
router.push("/users/eduardo");
// 带有路径的对象
router.push({ path: "/users/eduardo" });
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: "user", params: { username: "eduardo" } });
// 带查询参数,结果是 /register?plan=private
router.push({ path: "/register", query: { plan: "private" } });
// 带 hash,结果是 /about#team
router.push({ path: "/about", hash: "#team" });当path参数存在时,params会被忽略
// `params` 不能与 `path` 一起使用
router.push({ path: "/user", params: { username } }); // -> /user也可以使用字符串拼接出完整的path路径
const username = "eduardo";
// 我们可以手动建立 url,但我们必须自己处理编码
router.push(`/user/${username}`); // -> /user/eduardo
// 同样
router.push({ path: `/user/${username}` }); // -> /user/eduardo
// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益
router.push({ name: "user", params: { username } }); // -> /user/eduardo当指定 params 时,可提供 string 或 number 参数(或者对于可重复的参数可提供一个数组)。任何其他类型(如 undefined、false 等)都将被自动字符串化。对于可选参数,你可以提供一个空字符串("")来跳过它。
router.replace() | 编程式 
用法和router.push()一样,甚至可以用router.push()代替(在传递给 router.push 的 routeLocation 中增加一个属性 replace: true)
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })router.go() | 编程式 
类似window.history.go(n)
// 向前移动一条记录,与 router.forward() 相同
router.go(1);
// 返回一条记录,与 router.back() 相同
router.go(-1);
// 前进 3 条记录
router.go(3);
// 如果没有那么多记录,静默失败
router.go(-100);
router.go(100);name | 命名路由 
优点:
- 没有硬编码的 URL
- params的自动编码/解码。
- 防止你在 url 中出现打字错误。
- 绕过路径排序(如显示一个)
const routes = [
  {
    path: "/user/:username",
    name: "user",
    component: User,
  },
];name | 命名视图 
使用并列而不是嵌套的方法摆放几个路由
<router-view class="view left-sidebar" name="LeftSidebar"></router-view>
<!-- name不声明则默认为defult -->
<router-view class="view main-content"></router-view>
<router-view class="view right-sidebar" name="RightSidebar"></router-view>路由配置(注意使用 components而不是 component)
const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    {
      path: "/",
      components: {
        default: Home,
        // LeftSidebar: LeftSidebar 的缩写
        LeftSidebar,
        // 它们与 `<router-view>` 上的 `name` 属性匹配
        RightSidebar,
      },
    },
  ],
});案例 | 嵌套命名试图 
/settings/emails                                       /settings/profile
+-----------------------------------+                  +------------------------------+
| UserSettings                      |                  | UserSettings                 |
| +-----+-------------------------+ |                  | +-----+--------------------+ |
| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |
| |     +-------------------------+ |                  | |     +--------------------+ |
| |     |                         | |                  | |     | UserProfilePreview | |
| +-----+-------------------------+ |                  | +-----+--------------------+ |
+-----------------------------------+                  +------------------------------+- Nav只是一个常规组件。
- UserSettings是一个视图组件。
- UserEmailsSubscriptions、- UserProfile、- UserProfilePreview是嵌套的视图组件。
<!-- UserSettings.vue -->
<div>
  <h1>User Settings</h1>
  <NavBar />
  <router-view />
  <router-view name="helper" />
</div>// router
{
  path: '/settings',
  // 你也可以在顶级路由就配置命名视图
  component: UserSettings,
  children: [{
    path: 'emails',
    component: UserEmailsSubscriptions
  }, {
    path: 'profile',
    components: {
      default: UserProfile,
      helper: UserProfilePreview
    }
  }]
}redirect | 重定向 
// 从 /home 重定向到 /
const routes = [{ path: "/home", redirect: "/" }];
// 重定向的目标也可以是一个命名的路由
const routes = [{ path: "/home", redirect: { name: "homepage" } }];
// 方法作为重定向的目标,实现动态重定向
const routes = [
  {
    // /search/screens -> /search?q=screens
    path: "/search/:searchText",
    redirect: (to) => {
      // 方法接收目标路由作为参数
      // return 重定向的字符串路径/路径对象
      return { path: "/search", query: { q: to.params.searchText } };
    },
  },
  {
    path: "/search",
    // ...
  },
];请注意,导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。在上面的例子中,在 /home 路由中添加 beforeEnter 守卫不会有任何效果。
在写 redirect 的时候,可以省略 component 配置,因为它从来没有被直接访问过,所以没有组件要渲染。唯一的例外是嵌套路由:如果一个路由记录有 children 和 redirect 属性,它也应该有 component 属性。
相对重定向 
const routes = [
  {
    // 将总是把/users/123/posts重定向到/users/123/profile。
    path: "/users/:id/posts",
    redirect: (to) => {
      // 该函数接收目标路由作为参数
      // 相对位置不以`/`开头
      // 或 { path: 'profile'}
      return "profile";
    },
  },
];alias | 别名 
//  将/ 别名为 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /。
const routes = [{ path: "/", component: Homepage, alias: "/home" }];
//
const routes = [
  {
    path: "/users",
    component: UsersLayout,
    children: [
      // 为这 3 个 URL 呈现 UserList
      // - /users
      // - /users/list
      // - /people
      // 使用数组提供多个别名
      { path: "", component: UserList, alias: ["/people", "list"] },
    ],
  },
];如果你的路由有参数,请确保在任何绝对别名中包含它们:
const routes = [
  {
    path: "/users/:id",
    component: UsersByIdLayout,
    children: [
      // 为这 3 个 URL 呈现 UserDetails
      // - /users/24
      // - /users/24/profile
      // - /24
      { path: "profile", component: UserDetails, alias: ["/:id", ""] },
    ],
  },
];props | 路由组件传参 
vue-router 中 props 有 3 种模式,分别将 3 种对象传入组件中
布尔模式 
当 props 设置为 true 时,route.params 将被设置为组件的 props。
<!-- xxx.vue -->
<script setup lang="ts">
const props = defineProps(["uid"]);
</script>
<template>
  <h1>{{ uid }}</h1>
</template>// router
const routes = [
  {
    // 参数名称要相同
    path: "/user/:uid",
    component: User,
    // 注意这个属性不能落下,不写template里面就不能用
    props: true,
  },
];对于有命名视图的路由,你必须为每个命名视图定义 props 配置:
const routes = [
  {
    path: "/user/:id",
    components: { default: User, sidebar: Sidebar },
    props: { default: true, sidebar: false },
  },
];对象模式 
当 props 是一个对象时,它将原样设置为组件 props。当 props 是静态的时候很有用。
const routes = [
  {
    path: "/promotion/from-newsletter",
    component: Promotion,
    props: { newsletterPopup: false },
  },
];函数模式 
你可以创建一个返回 props 的函数。这允许你将参数转换为其他类型,将静态值与基于路由的值相结合等等。
const routes = [
  {
    path: "/search",
    component: SearchUser,
    props: (route) => ({ query: route.query.q }),
  },
];URL /search?q=vue 将传递 {query: 'vue'} 作为 props 传给 SearchUser 组件。
