跳到主要内容

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,
},
},
];