vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue路由守卫

一文带你掌握Vue中的路由守卫

作者:JYeontu

路由守卫(Route Guards)是 Vue Router 的一个功能,它允许我们在路由发生之前执行逻辑判断,这篇文章主要为大家介绍了Vue中路由守卫的具体应用,需要的可以了解下

说在前面

在构建 Vue 应用程序时,路由守卫是确保流畅用户体验和强大逻辑控制的关键工具。本文将一起探讨 Vue 路由守卫的概念、类型和实际应用,帮助你理解如何利用这些守卫来增强应用的导航能力、实现权限控制和优化用户流程。

一、 简介

在构建现代 Web 应用程序时,路由管理是实现复杂页面结构和流畅用户体验的关键。Vue.js,作为一种流行的前端框架,通过 Vue Router 插件提供了强大的路由管理功能。在这个框架中,路由守卫(Route Guards)扮演着至关重要的角色,它们是确保应用程序导航逻辑正确性和增强用户体验的重要工具。

路由守卫的重要性在于它们提供了一种机制,允许我们在路由发生之前执行逻辑检查和操作。无论是验证用户权限、保护页面免受未授权访问,还是实现复杂的导航逻辑,路由守卫都能确保我们的应用程序在用户与界面交互时保持一致性和安全性。它们是开发者用来控制路由访问权限、管理页面转换和优化加载流程的强大盟友。

二、 Vue 路由守卫概念

什么是路由守卫

路由守卫(Route Guards)是 Vue Router 的一个功能,它允许我们在路由发生之前执行逻辑判断。这些守卫可以用来实现权限验证、页面访问控制、数据预加载等逻辑,确保用户在应用中的导航流程符合我们的业务需求。

路由守卫主要有以下几种类型:

1.全局守卫(Global Guards):

2.路由独享守卫(Route-specific Guards):

可以在路由配置中直接定义 beforeEnter 守卫,这些守卫只适用于特定的路由。

3.组件内守卫(Component-specific Guards):

路由守卫通过 next 函数来决定路由是否继续。next 函数可以接受三个参数:next()next(false) 或 next('/')。其中,next() 表示继续当前路由,next(false) 表示中断当前路由,next('/') 表示跳转到一个新路由。

使用路由守卫,我们可以在路由进入前进行条件判断,从而实现更细粒度的控制,确保用户只能访问他们有权限的页面,或者在页面跳转前完成必要的数据加载和验证。这是构建健壮、用户友好的 Vue 应用程序的重要工具之一。

路由守卫与导航流程的关系

路由守卫(Route Guards)与导航流程在 Vue 应用中的关系密切,它们共同构成了应用的路由导航机制。以下是它们之间的关系:

导航流程

在 Vue 应用中,用户可以通过点击链接、使用 vue-router 的 push 或 replace 方法,或者直接在浏览器地址栏输入 URL 来触发导航。导航流程通常包括以下几个步骤:

路由守卫

路由守卫是导航流程中的关键环节,它们可以在导航的不同阶段执行逻辑判断和处理:

关系

路由守卫与导航流程的关系可以这样理解:导航流程是导航发生的顺序和步骤,而路由守卫是嵌入到这个流程中的逻辑检查点。它们允许开发者在导航的关键时刻介入,根据应用的业务需求做出决策,如是否允许导航继续、是否需要重定向到其他路由、是否需要加载额外的数据等。

通过这种方式,路由守卫为 Vue 应用提供了灵活性和控制力,确保用户在应用中的导航体验既安全又高效。开发者可以利用路由守卫来保护资源、优化性能和提升用户体验。

三、全局守卫

beforeEach 和 afterEach 全局守卫

beforeEach 和 afterEach 是 Vue Router 提供的全局守卫,它们允许你在路由导航的前后执行逻辑,这些守卫可以用于所有路由的导航,不仅限于特定的路径或组件。

beforeEach 全局前置守卫

beforeEach 是在路由进入之前全局调用的守卫。它是导航过程中最早被调用的守卫,可以用来做权限验证、重定向未认证用户、记录日志等。如果这个守卫返回 false 或调用 next(false),当前导航将中断;如果调用 next() 或 next(true),则导航继续。

router.beforeEach((to, from, next) => {
  // 检查用户是否已登录,如果未登录,重定向到登录页面
  if (to.meta.requiresAuth) {
    if (isAuthenticated()) {
      next(); // 用户已登录,允许访问
    } else {
      next({ path: '/login' }); // 用户未登录,重定向到登录页面
    }
  } else {
    next(); // 无需验证,继续导航
  }
});

afterEach 全局后置守卫

afterEach 是在路由确认之后调用的守卫,它在导航完成后执行,不会接收 next 函数也不会改变导航本身。这个守卫通常用于记录用户的行为、更新页面标题、清理资源等。

router.afterEach((to, from) => {
  // 记录路由访问日志
  console.log(`Navigated to ${to.path}`);
  // 设置页面标题
  document.title = to.meta.title;
  // 执行其他清理或更新操作
});

应用场景

全局守卫是 Vue 应用中控制路由行为的强大工具,它们使得开发者能够在全局范围内对路由进行统一管理。通过合理使用这些守卫,可以提升应用的安全性、用户体验和性能。

实例:实现全局权限验证

要实现全局权限验证,你可以使用 Vue Router 的 beforeEach 全局前置守卫。这个守卫会在路由跳转之前运行,因此它是检查用户权限的理想位置。以下是一个简单的实例,展示了如何实现全局权限验证:

// 假设你有一个方法来检查用户是否已经登录
const isAuthenticated = () => {
  // 这里应该是你的认证逻辑,例如检查本地存储或会话中的 token
  // 返回 true 如果用户已登录,否则返回 false
  return localStorage.getItem('userToken') !== null;
};

// 假设你有一个路由配置对象
const router = new VueRouter({
  // ...你的路由配置
});

// 全局前置守卫
router.beforeEach((to, from, next) => {
  // 如果路由需要认证(例如,不是登录页面)
  if (to.matched.some(record => record.meta.requiresAuth)) {
    // 检查用户是否已登录
    if (isAuthenticated()) {
      // 用户已登录,允许访问
      next();
    } else {
      // 用户未登录,重定向到登录页面
      next({
        path: '/login',
        query: { redirect: to.fullPath } // 保存要重定向的路由
      });
    } else {
      // 如果用户尝试访问不需要认证的路由,直接放行
      next();
    }
  } else {
    // 路由不需要认证,直接放行
    next();
  }
});

// 然后你可以在你的 Vue 应用中使用这个路由器
new Vue({
  router,
  // ...其他选项
});

在这个例子中,我们首先定义了一个 isAuthenticated 方法,它应该包含你的认证逻辑,例如检查用户的登录状态。然后,我们在 beforeEach 全局前置守卫中检查即将访问的路由是否需要认证。如果用户已经登录,我们就允许路由继续;如果用户未登录,我们就将用户重定向到登录页面,并保存当前想要访问的路由路径,以便登录后可以返回。

请注意,这个例子假设你已经在本地存储(如 localStorage)中保存了一个表示用户登录状态的标记(例如,token)。你需要根据你的后端认证系统来实现 isAuthenticated 方法的具体逻辑。此外,你可能还需要在用户登录后更新 localStorage 中的标记,并在用户登出时清除它。

实例:记录用户导航日志

要记录用户的导航日志,你可以使用 Vue Router 的 afterEach 全局后置守卫。这个守卫在路由导航确认之后被调用,可以用来记录用户访问的页面信息。以下是一个简单的实例:

import router from './router'; // 假设你已经定义了一个 router 对象

// 日志记录函数
function logNavigation(to, from) {
  console.log(`User navigated from ${from.path} to ${to.path}`);
  // 这里你可以将日志信息发送到服务器,或者存储在本地
}

// 使用全局后置守卫记录导航日志
router.afterEach(logNavigation);

// 现在,每当用户导航到新路由时,logNavigation 函数都会被调用

在这个例子中,我们定义了一个 logNavigation 函数,它接收两个参数:to 和 fromto 对象包含用户即将导航到的路由信息,而 from 对象包含用户从哪个路由导航过来。这个函数被用作 afterEach 守卫的回调,因此它会在每次导航完成后被调用。

你可以将这个日志记录函数扩展为更复杂的逻辑,例如:

请注意,如果你选择将日志信息发送到服务器,你可能需要在 logNavigation 函数中调用一个异步的日志上传函数,并确保在发送日志之前用户已经成功导航到新路由。这可以通过在 next 函数调用之后执行日志上传来实现。

四、路由独享守卫

路由独享守卫的用法

路由独享守卫是针对特定路由的守卫,它们只在特定路由被访问时触发。这些守卫可以在路由配置中直接定义,用于执行与该路由相关的逻辑,如权限检查、数据预加载等。

路由独享守卫的用法示例

假设你有一个用户 dashboard 页面,只有管理员才能访问。你可以在路由配置中为这个路由添加一个 beforeEnter 守卫来确保只有管理员可以访问:

const router = new VueRouter({
  routes: [
    {
      path: '/dashboard',
      component: DashboardComponent,
      meta: { requiresAuth: true }, // 路由元信息,标记此路由需要认证
      beforeEnter: (to, from, next) => {
        // 检查用户是否为管理员
        if (userIsAdmin()) {
          next(); // 允许进入
        } else {
          next({ path: '/' }); // 非管理员用户重定向到首页
        }
      }
    },
    // ...其他路由
  ]
});

在这个例子中,userIsAdmin 是一个假设的函数,用来检查当前用户是否具有管理员权限。如果用户是管理员,next() 被调用,允许路由继续;如果不是,next({ path: '/' }) 被调用,用户将被重定向到首页。

路由独享守卫的特点

注意事项

通过使用路由独享守卫,你可以为每个路由定制特定的导航逻辑,从而更好地控制应用的路由行为和用户体验。

实例:为特定路由添加访问限制

为特定路由添加访问限制通常涉及到权限验证。以下是一个实例,展示了如何为一个假设的后台管理系统中的 /admin 路由添加访问限制,确保只有具有管理员权限的用户才能访问:

import Vue from 'vue';
import VueRouter from 'vue-router';
import AdminComponent from './components/AdminComponent.vue';
import LoginComponent from './components/LoginComponent.vue';

Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    component: LoginComponent, // 默认重定向到登录页面
  },
  {
    path: '/admin',
    component: AdminComponent,
    meta: { requiresAuth: true }, // 标记此路由需要认证
    // 路由独享守卫
    beforeEnter: (to, from, next) => {
      // 假设有一个方法来检查用户是否是管理员
      const isAdmin = checkIfAdmin();
      if (isAdmin) {
        next(); // 用户是管理员,允许访问
      } else {
        next('/'); // 用户不是管理员,重定向到首页或其他允许访问的页面
      }
    },
  },
  // ...其他路由
];

const router = new VueRouter({
  routes,
});

function checkIfAdmin() {
  // 这里应该是你的认证逻辑,例如检查本地存储中的管理员令牌
  // 返回 true 如果用户是管理员,否则返回 false
  return localStorage.getItem('adminToken') !== null;
}

export default router;

在这个例子中,我们定义了一个 checkIfAdmin 函数,它应该包含你的管理员权限验证逻辑。我们假设管理员权限是通过一个存储在本地存储中的令牌来标识的。如果用户是管理员,next() 被调用,允许路由继续;如果用户不是管理员,next('/') 被调用,用户将被重定向到首页或其他允许访问的页面。

请注意,这个例子假设你已经在本地存储中保存了一个表示用户管理员状态的标记(例如,adminToken)。你需要根据你的后端认证系统来实现 checkIfAdmin 函数的具体逻辑,并在用户登出时清除这个标记。

通过这种方式,你可以为 Vue 应用中的特定路由添加访问限制,确保只有具有相应权限的用户才能访问敏感内容。

五、组件内守卫

beforeRouteEnter、beforeRouteUpdate 和 beforeRouteLeave 守卫

在 Vue 路由中,beforeRouteEnterbeforeRouteUpdate 和 beforeRouteLeave 是组件级别的导航守卫,它们允许你在组件内部控制路由的导航行为。这些守卫是 Vue 组件的生命周期钩子,可以在组件实例化的不同阶段被调用。

beforeRouteEnter 守卫

beforeRouteEnter 是在路由配置为当前路由,但组件实例尚未创建时调用的守卫。这意味着你不能在 beforeRouteEnter 守卫中访问组件实例的 this,因为它还没有被创建。这个守卫通常用于执行不需要组件实例的逻辑,如验证路由的合法性。

export default {
  // ...
  beforeRouteEnter(to, from, next) {
    // 验证逻辑,例如检查用户权限
    next(); // 放行
    next(false); // 禁止访问
    next({ path: '/some-path' }); // 重定向到其他路由
  },
  // ...
};

beforeRouteUpdate 守卫

beforeRouteUpdate 是在当前路由改变,但该组件被复用时调用的守卫。例如,当用户在 /user/1 和 /user/2 之间切换时,因为这两个路由使用了相同的组件,所以 beforeRouteUpdate 会被调用。这个守卫可以用来处理组件激活时的相关逻辑,如数据预加载。

export default {
  // ...
  beforeRouteUpdate(to, from, next) {
    // 可以访问组件实例的 this
    // 例如,你可以在这里加载 to.params.id 对应的数据
    next(); // 必须调用 next() 以允许导航继续
  },
  // ...
};

beforeRouteLeave 守卫

beforeRouteLeave 是在离开该组件的对应路由时调用的守卫。这个守卫可以用来阻止用户在未保存修改的情况下离开,或者执行一些清理工作。

export default {
  // ...
  beforeRouteLeave(to, from, next) {
    // 可以访问组件实例的 this
    // 例如,提示用户保存修改
    if (needToSave()) {
      next(new Promise((resolve, reject) => {
        saveData(() => {
          // 数据保存成功后,继续导航
          resolve();
        }, () => {
          // 用户取消保存,留在当前页面
          reject();
        });
      }));
    } else {
      next(); // 无需保存,直接导航
    }
  },
  // ...
};

在这个例子中,needToSave 是一个假设的函数,用来检查是否有需要保存的数据。saveData 是一个假设的函数,用来执行数据保存操作。beforeRouteLeave 守卫通过返回一个 Promise 来等待数据保存操作完成,确保用户不会在数据未保存的情况下离开。

总结

这些守卫为 Vue 组件提供了在路由变化时执行复杂逻辑的能力,增强了组件的响应性和交互性。使用这些守卫时,记得始终调用 next 函数来控制路由的导航流程。

实例:组件级别的权限控制

组件级别的权限控制通常涉及到检查用户是否有权访问特定的组件。以下是一个示例,展示了如何在 Vue 组件中使用 beforeRouteEnter 守卫来实现权限控制:

<template>
  <div>
    This is a protected admin page.
  </div>
</template>

<script>
export default {
  name: 'AdminPage',
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被确认前调用
    // 不能访问组件实例 `this`
    checkPermission(to, from, next);
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 可以访问组件实例 `this`
    checkPermission(to, from, next);
  },
  methods: {
    checkPermission(to, from, next) {
      // 假设有一个方法来检查用户是否具有管理员权限
      if (isUserAdmin()) {
        next(); // 用户具有权限,允许访问
      } else {
        next({ path: '/unauthorized' }); // 用户没有权限,重定向到无权限页面
      }
    }
  }
};
</script>

在这个例子中,checkPermission 方法用于验证用户是否具有访问 AdminPage 的权限。如果用户是管理员,next() 被调用,允许路由继续;如果不是,用户将被重定向到一个无权限访问的页面。

实例:数据预加载和表单保护

数据预加载是在组件渲染之前加载所需数据的过程,而表单保护是防止用户在表单填写一半时离开页面而丢失数据的机制。以下是一个示例,展示了如何在 Vue 组件中使用 beforeRouteUpdate 和 beforeRouteLeave 守卫来实现这两功能:

<template>
  <div>
    <form @submit.prevent="onSubmit">
      <!-- 表单输入字段 -->
    </form>
    <button @click="saveDraft">Save Draft</button>
  </div>
</template>

<script>
export default {
  name: 'FormPage',
  data() {
    return {
      formData: {}
    };
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 用于数据预加载
    this.fetchFormData();
    next();
  },
  beforeRouteLeave(to, from, next) {
    // 在离开该组件的对应路由时调用
    // 用于表单保护
    if (this.isFormDirty()) {
      const answer = confirm('You have unsaved changes. Are you sure you want to leave?');
      if (answer) {
        next(); // 用户确认离开,允许导航
      } else {
        next(false); // 用户取消离开,阻止导航
      }
    } else {
      next(); // 没有未保存的更改,允许导航
    }
  },
  methods: {
    fetchFormData() {
      // 从服务器获取表单数据
    },
    onSubmit() {
      // 提交表单
    },
    saveDraft() {
      // 保存表单草稿
    },
    isFormDirty() {
      // 检查表单是否有未保存的更改
    }
  }
};
</script>

在这个例子中,beforeRouteUpdate 守卫用于在用户导航到新的表单路由时预加载表单数据。beforeRouteLeave 守卫用于在用户离开表单页面时提示保存更改。如果表单有未保存的更改,用户将被提示确认是否离开,从而避免数据丢失。

六、高级路由守卫应用

路由守卫的高级用法,如滚动行为控制、路由元信息等

Vue 路由守卫除了基本的导航控制和权限验证外,还有一些高级用法,可以帮助你更细致地管理路由行为,例如控制滚动行为和利用路由元信息。

滚动行为控制

Vue Router 默认会在路由跳转后,将滚动条回到页面顶部。在某些情况下,你可能希望保持滚动位置不变,或者滚动到特定位置。你可以通过设置路由的 scrollBehavior 函数来控制滚动行为。

const router = new VueRouter({
  // ...
  scrollBehavior(to, from, savedPosition) {
    if (to.hash) {
      // 如果路由包含锚点,则滚动到锚点
      return {
        selector: to.hash,
        behavior: 'smooth'
      };
    } else if (from.path === to.path) {
      // 如果是相同路由的复用(如通过按钮切换视图),保持当前滚动位置
      return savedPosition;
    } else {
      // 否则,滚动到顶部
      return { top: 0 };
    }
  }
});

路由元信息

路由元信息(meta fields)允许你在路由配置中添加额外的数据,这些数据可以用于守卫逻辑判断,或者在组件内部使用。

const routes = [
  {
    path: '/user/:id',
    component: UserComponent,
    meta: {
      // 路由元信息
      requiresAuth: true, // 需要认证
      isBeta: false // 标记为 Beta 功能
    }
  }
  // ...其他路由
];

然后,你可以在守卫中使用这些元信息来进行决策:

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    // 检查用户是否已登录
    if (isAuthenticated()) {
      next();
    } else {
      next({ path: '/login' });
    }
  } else {
    next();
  }
});

在这个例子中,我们检查即将进入的路由是否有 requiresAuth 元信息。如果有,我们再检查用户是否已登录,以决定是否允许用户访问该路由。

高级用法示例

结合滚动行为控制和路由元信息,你可以创建一个高级路由守卫,它根据路由的元信息来决定是否允许访问,并控制滚动行为:

router.beforeEach((to, from, next) => {
  // 检查路由是否为 Beta 功能
  if (to.meta.isBeta) {
    if (isBetaUser()) {
      next({
        scroll: false // 不滚动到顶部
      });
    } else {
      next('/beta-redirect'); // 非 Beta 用户重定向到特定页面
    }
  } else {
    next({
      scroll: { top: 0 } // 默认滚动到顶部
    });
  }
});

在这个例子中,我们首先检查目标路由是否有 isBeta 元信息。如果有,我们检查用户是否有权访问 Beta 功能。根据结果,我们决定是否允许用户访问,并设置滚动行为。

通过这些高级用法,你可以更精细地控制路由的行为,从而提供更好的用户体验。

七、结论

路由守卫(Route Guards)在 Vue 应用程序中提供了多种优势,特别是在管理用户导航和执行特定逻辑时。以下是路由守卫的一些主要优势:

总之,路由守卫是 Vue 路由系统的重要组成部分,它们为开发者提供了强大的工具来管理应用程序的路由行为,保护资源,以及优化用户导航体验。

八、附录

Vue 路由官方文档快速入口

Vue 路由(Vue Router)的官方文档可以在 Vue.js 的官方网站找到。以下是快速入口的链接:

Vue Router 官方文档

在这个页面上,你可以找到关于 Vue 路由的所有信息,包括安装指南、基本用法、路由守卫、路由元信息、导航、链接、命名路由、重定向和别名等。官方文档还提供了各种示例和最佳实践,帮助你更好地理解和使用 Vue 路由。

以上就是一文带你掌握Vue中的路由守卫的详细内容,更多关于Vue路由守卫的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文