跳到主要内容

vue-router

RouterLink 组件代替 a 标签.

RouterView 在哪里渲染当前 url 路径对应的路由组件.

$route 变量.

细节

路由命名的一些问题

{
path: "/user/:id",
name: "user",
component: UserPage,
children: [
{
path: "profile",
name: "profile",
component: UserProfile
},
{
path: "posts",
name: "posts",
component: UserPosts
},
{
path: "",
name: "root",
component: UserRoot
}
]
}
  • router.push('/user/123') 会渲染 UserRoot 组件.
  • router.push({ name: 'user', params: { id: '123' } }) 不会渲染 UserRoot 组件.

命名路由的优点

命名必须唯一

  • 没有硬编码
  • params 自动编解码
  • 避免 typo
  • 绕过路径排序, 例如展示一个匹配路径相同但排序较低的路由.

编程式导航

router.push() 时, 如果传了 path, 那么 params 会被忽略, ts 环境下, 编译器会进行提示.

params 会自动将非 string, number 参数转成 string 类型.

router.push 会返回一个 Promise 对象

匹配当前路由的链接

router-link-active, router-link-exact-active

  1. 与当前路径匹配相同的路由记录
  2. params 与 当前路径的 params 相同

守卫

全局前置守卫

每次导航都会执行.

安装定义的先后顺序依次执行.

let isAuthenticated = false;
router.beforeEach(async (to) => {
console.log("guard 3");
if (!isAuthenticated && to.name !== "login") {
isAuthenticated = true;
// 重定向至 name = 'login' 的路由
return {
name: "login",
};
}
// 允许导航
return true;
});

router.beforeEach 运行创建多个前置守卫.

全局解析守卫

每次导航都会执行.

解析守卫会在导航被确认之前,所有组件内守卫异步路由组件被解析之后调用.

router.beforeResolve 是获取数据或执行任何其他操作的理想位置.

router.beforeResolve(() => {
console.log("解析守卫");
});

全局后置钩子

不会改变导航.

一般用于分析,更改页面标题,声明页面等辅助功能,以及许多其他事情.

在守卫内的全局注入

const app = createApp(App);
app.provide("global", "hello injections");

// router.ts or main.ts
router.beforeEach((to, from) => {
const global = inject("global"); // 'hello injections'
// a pinia store
const userStore = useAuthStore();
// ...
});

app.provide 提供的内容,在 router.beforeEach(), router.beforeResolve(), router.afterEach() 内可以获取到.

路由独享守卫

  {
path: "/user/:username",
component: UserPage,
props: true,
beforeEnter: (to) => {
console.log("路由独享守卫");
if (to.params.username === "admin") {
return {
name: "login",
};
}
},
children: [
{
path: "role/:roleId",
component: RolePage,
props: true,
},
],
},

路由独享守卫只在进入路由时触发, params, query, hash 变化不出改变时不会触发.

  • /user/abc --> /user/aaa 不会触发
  • /user/abc?a=1 --> /user/abc?a=2 不会触发
  • /user/abc#info --> /user/abc#projects 不会触发
  • /user/abc/role/1 --> /user/abc/role/2 不会触发
  • /user/abc/role/1 --> /user/def/role/1 不会触发

beforeEnter 可以传入一个函数数组.

守卫的执行顺序

/user/a --> /user/b

  • 全局前置守卫 beforeEach
  • 组件update守卫 beforeRouteUpdate
  • 全局解析式后卫 beforeResolver
  • 全局后置钩子 afterEach

/user/a --> /login/

  • 组件leave守卫 beforeRouteLeave
  • 全局前置守卫 beforeEach
  • 路由独享守卫 beforeEnter
  • 组件enter守卫 beforeRouteEnter 此方法内不能使用this,组件实例还未创建
  • 全局解析守卫 beforeResolver
  • 全局后置钩子 afterEach

/user/a --> /user/a

  • 全局后置钩子 afterEach

完整的导航解析流程

  1. 导航被触发
  2. 组件leave守卫
  3. 全局前置守卫
  4. 组件内路由变化 ? 组件update守卫
  5. 由其他路由跳转过来 ? 路由独享守卫
  6. 解析异步路由组件, 需要在导航确认之前完成组件加载.
  7. 组件enter守卫
  8. 全局解析守卫
  9. 导航被确认
  10. 全局后置守卫
  11. DOM 更新
  12. 调用 beforeRouteEnter 传给 next 的回调函数.

获取数据

导航完成之后获取(通过组件的声明周期函数获取)

导航完成之前获取(在路由进入的守卫中获取)

vue 编程规范

.vue 文件 script 代码顺序规范

  1. import 语句
  2. 类型定义: interface, type 等
  3. Props 定义
  4. Emits 定义
  5. 响应式状态: ref, reactive, computed 等
  6. 工具,辅助函数
  7. API 请求函数
  8. 业务逻辑函数
  9. 监听器: watch, watchEffect
  10. 生命周期钩子

滚动行为

const router = createRouter({
routes,
// history: createWebHistory()--> history 模式, createWebHashHistory() ---> hash 模式
// history: createMemoryHistory(),
// history:createWebHistory(),
// history: createWebHistory(),
history: createWebHashHistory(),
// 路径匹配
linkActiveClass: "bg-gray-400",
// 精准匹配
linkExactActiveClass: "bg-green-400",
// 切换路由时的滚动行为
scrollBehavior(to, from, savedPosition) {
// 1. 滚动到顶部
// return { top: 0 };
// 2. 相对于指定 dom 的偏移量
// return {
// el: document.getElementById("app"),
// // el: "#app",
// top: -110,
// };
// 3. savedPosition,只有当这是一个 popstate 导航时才可用(由浏览器的后退/前进按钮触发)。
// if (savedPosition) {
// return savedPosition;
// } else {
// return {
// top: 0,
// };
// }
// 4. 滚动到锚点
// if (to.hash) {
// return {
// el: to.hash,
// behavior: "smooth",
// };
// }
// 5. 延迟滚动
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve({
// left: 0,
// top: 0,
// });
// }, 500);
// });
},
});
  1. 滚动到顶部
  2. 相对于指定 dom 的偏移量
  3. savedPosition
  4. 滚动到锚点
  5. 延迟滚动

路由懒加载

// 懒加载
const LoginPage = () => import("@/views/LoginPage.vue");

const routes: RouteRecordRaw[] = [
{
name: "login",
path: "/login",
component: LoginPage,
beforeEnter: [
(to, from) => {
console.log(`路由独享守卫, '${from.path}' to '${to.path}' `);
if (isAuthenticated) {
return {
name: "welcome",
};
}
},
],
// 将信息附加给路由
meta: {
requiresAuth: false,
},
},
{
path: "/welcome",
alias: "/",
name: "welcome",
// 懒加载
component: () => import("@/pages/WelcomePage.vue"),
props: true,
meta: {
requiresAuth: false,
},
},
];