动态路由和路由导航守卫及其案例分析

news2025/3/12 21:33:16

为什么需要动态路由?

动态路由其实用的不多,在实际开发中,如果遇到权限分配问题,比如对于一个公司人员的后台管理系统,那对不同成员的权限肯定不同,对于人事部,他们有权限进入成员表对人员的流动进行管理,对于技术部,他们有权上传任务进度来进行团队协作等等。对于不同人员,界面的渲染也不能相同。在有一些公司中可能会采用隐藏组件来实现权限的分配,但这样治标不治本:路由还是注册了,理论上只要知道路径,即使没有相应的组件来进入目标页面,也可以通过映射关系进入。这就会产生bug,所以有时会采用动态路由。

动态路由,顾名思义,就是在一定条件下才会注册路由,要不然根本不注册,脱离了路由就失去了映射关系,这样就不会出现bug了。

动态路由

其实动态路由核心就只有一个:addRoute方法,在这个方法中,可以传入一个对象,填入path,component,query等参数。

let isAdmin = true
if (isAdmin) {
router.addRoute({
path: "/admin",
component: () => import("@/Views/Admin.vue")
})
}

//嵌套写法
 if (isAdmin){
   router.addRoute("home",{
     path:"/home/vip",
     component: ()=> import("")
   })
 }

以上只是模拟一下权限的分配,真实情况下权限的分配是根据服务器传回来的响应来决定的。

当isAdmin为true时,说明权限为管理员,这时我们就给其注册路由,创建Admin.vue与"/admin"的映射关系。

当然,想要移除也是同理,使用removeRoute方法,传入路由的name。

路由导航守卫⭐

了解路由导航守卫前,我们只要了解一个业务就能很好理解:

对于刚进入淘宝的游客,他可以浏览商品但是当购买商品时不会跳转到购买界面而是会重定向到登录/注册界面,只有当注册/登录完成后服务器返回用户特定的token后才会允许他进入购买界面,生成token那是后端的逻辑,暂且不论。对于重定向,路由导航守卫起到很大作用:导航守卫会在用户每次前往某个界面前先检查一下用户是否满足条件,如果不满足条件就会执行回调函数,一般是重定向,在满足条件后可以正常进入。

视频分析 

接下来,我们结合一个视频案例来说明路由导航守卫最终的效果

2024-09-03 22-34-47

代码分析

在这篇文章仅仅展示路由导航守卫用到的代码,关于其他的代码可以翻阅上篇文章。

App.vue

<template>
  <div class="app">
    <div class="main-nav">
      <!-- <router-link to="/home" replace>首页</router-link>  replace 替换路径,不会记录历史路径--> 
      <!-- <router-link to="/home" active-class="link-class">首页</router-link> active-class指定选中的元素附带的className -->
      <ul class="nav-bar">
        <li @click="homeLiClick">首页</li>
        <li @click="aboutLiClick">关于</li>
        <li @click="userLiClick">用户</li>
      </ul>
    </div>
    <router-view></router-view> 
  </div>


  <!-- 编程式跳转页面 -->
  
</template>

<script setup>
import { useRouter } from 'vue-router';
const router = useRouter()



function homeLiClick(){
  router.push({
    path:"/home",
    query:{}
  })
}
function aboutLiClick(){
  router.push({
    path:"/about",
    query:{
      name:"Lisman",
      age:"18",
      sex:"male"
    }
  })
}
function userLiClick(){
  router.push({
    path:"/user",
    query:{
      name:"Lisman",
      password:"123456"
    }
  })
}


</script>

<style lang="less" scoped>
.main-nav {
  
  .nav-bar{
    list-style-type: none;
    display: flex;
    margin: 0;
    padding: 0;
    text-align: center;
    height: 44px;
    width: 100%;
    line-height: 44px;
    

    li{
      flex: 1;
      background-color: #454545;
      color: whitesmoke;
      font-size: 14px;
      font-weight: bold;
      cursor: pointer;
    }
  }
}

</style>

Login.vue

<template>
  <div class="login">
    <div class="container">
      <div class="header">
        <span>Admin Login</span>
      </div>
      <div class="content">
        <div class="login-content">
          <label for="username">
          username 
          <input type="text" name="username">
        </label>
        <label for="password">
          password 
          <input type="text" name="password">
        </label>
        <button @click="loginBtnClick">登录</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { useRouter } from 'vue-router';
const router = useRouter()
function loginBtnClick(){
  window.localStorage.setItem("token","12234FFASSD")
  router.push({
    path:"/user",
    query:{
      name:"Lisman",
      password:"123456"
    }
  })
}
</script>

<style lang="less" scoped>
.login{
  height: 1000px;
  background-color: #c9c9c9;
  position: relative;

  .container{
    height: 400px;
    width: 50%;
    background-color: #fff;
    position: absolute;
    top:200px;
    left:25%;
    border-radius: 10px;
    .header{
      width: 80%;
      margin: 0 auto;
      height: 100px;
      text-align: center;
      line-height: 100px;
        span{
        font-weight: bold;
        font-size: 30px;
        padding-bottom: 3px;
        border-bottom: 2px solid black;
      }
    }
    .content{
      height: 255px;
      background-color: aquamarine;
      width: 75%;
      margin: 0 auto;
      border-radius: 10px;
      .login-content{
        width: 75%;
        height: 100px;
        margin: 0 auto;
        padding-top: 30px;
        position: relative;
        label{
          display: block;
          margin-bottom: 20px;
          margin-top: 30px;
          margin-left: 100px;
        }
        button{
          position: absolute;
          top: 170px;
          left: 340px;
        }
        
      }
    }

  }
}
</style>

User.vue

<template>
  <div class="user">
    <div class="container">
      <div class="header">
        <span>User Info</span>
      </div>
      <div class="content">
        <div class="user-info">
          <h2 class="username">Username : {{ $route.query.name }}</h2>
          <h2 class="password">Password : {{ $route.query.password }}</h2>
          <button @click="logoutBtnClick">退出登录</button>
        </div>

      </div>
    </div>
  </div>
</template>

<script setup>
import { useRouter } from 'vue-router';

const router = useRouter()

function logoutBtnClick(){
  window.localStorage.removeItem("token")
  router.push("/home")
}
</script>

<style lang="less" scoped>
.user{
  height: 1000px;
  background-color: #c9c9c9;
  position: relative;

  .container{
    height: 400px;
    width: 50%;
    background-color: #fff;
    position: absolute;
    top:200px;
    left:25%;
    border-radius: 10px;
    .header{
      width: 80%;
      margin: 0 auto;
      height: 100px;
      text-align: center;
      line-height: 100px;
        span{
        font-weight: bold;
        font-size: 30px;
        padding-bottom: 3px;
        border-bottom: 2px solid black;
      }
    }
    .content{
      height: 255px;
      background-color: aquamarine;
      width: 75%;
      margin: 0 auto;
      border-radius: 10px;
      .user-info{
        width: 75%;
        height: 100px;
        margin: 0 auto;
        padding-top: 30px;
        position: relative;
        text-align: center;
        h2{
          padding-top: 20px;
        }
        
      }
    }

  }
}
</style>

index.js

import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'

//导入组件
// import Home from '@/Views/Home.vue'
// import About from '@/Views/About.vue'


//以下为路由懒加载,import导入可以做到分包处理,webpackChunkName可以给包指定名字
// const Home = import(/* webpackChunkName: 'Home' */"../Views/Home.vue")
// const About = import(/* webpackChunkName: 'About' */"../Views/About.vue")

//创建路由:映射关系
const router = createRouter({
  //选择模式(Hash)
  // history: createWebHashHistory(),
  history: createWebHashHistory(),
  routes: [
    {
      path: "/home",
      component: () => import("../Views/Home.vue"),
      //嵌套路由
      children: [
        {
          path: "recommend",//相当于/home/recommend
          component: () => import("../Views/Recommend.vue")
        },
        {
          path: "ranking",
          component: () => import("../Views/Ranking.vue")
        },
        {
          path: "",
          redirect: "/home/recommend"
        }
      ]
    },
    { path: "/about", component: () => import("../Views/About.vue") },
    { path: "/", redirect: "/home" },
    { path: "/:pathMatch(.*)", component: () => import("../Views/NotFound.vue") },
    { path: "/login", component: () => import("@/Views/Login.vue") },
    { path: "/user", component: () => import("@/Views/User.vue") }
  ]
})

// let isAdmin = true
// if (isAdmin) {
//   router.addRoute({
//     path: "/admin",
//     component: () => import("@/Views/Admin.vue")
//   })
// }

//嵌套写法
// if (isAdmin){
//   router.addRoute("home",{
//     path:"/home/vip",
//     component: ()=> import("")
//   })
// }

//路由守卫,每次跳转都会执行回调
router.beforeEach((to, from) => {
  const token = window.localStorage.getItem("token")
  if (to.path === "/user" && !token) {
    return "/login"
  }
})

//导出路由
export default router

框图分析 

以下为图例:

其实有关路由导航守卫的只要一段代码,其他部分主要是界面和token的获取和设置。

router.beforeEach((to, from) => {
  const token = window.localStorage.getItem("token")
  if (to.path === "/user" && !token) {
    return "/login"
  }
})

beforeEach()方法会在进入每个路径前激活它的回调函数,它拥有两个参数:to,from,to为目标路由,from为原来的路由,我们首先检查一下用户是否拥有token,判断目标路径是否为/user,如果没有token,那么就满足条件而重定向到/login。如果拥有token,那么就不满足条件,返回undefined,在beforeEach中如果返回undefined那就不做操作,该去哪去哪,守卫不会作用。

当然守卫不只beforeEach一种,不同的守卫应结合实际开发情况来使用,关于其他的守卫文档我放在下面了:

https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2102046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络安全】XSS漏洞挖掘Tip

未经许可&#xff0c;不得转载。 某网页存在错误信息&#xff0c;包含在div标签内&#xff1a; 检查此页面的源代码以获取id属性&#xff1a; 将id属性作为 GET 参数进行测试&#xff0c;例如在 URL 中添加error_messagehelloworld&#xff1a; 可以看到&#xff0c;参数被接受…

流媒体技术革新,EasyCVR视频汇聚平台赋能视频监控全面升级

随着科技的飞速发展&#xff0c;流媒体技术和视频监控正经历着前所未有的变革与融合。本文将从流媒体技术的新兴趋势出发&#xff0c;探讨其与视频监控领域的深度结合&#xff0c;以及这一融合所带来的创新与发展。 一、流媒体技术的新兴趋势 1、5G网络的广泛应用 5G网络以其…

AI驱动测试管理工具会有哪些发展前景呢?

在软件测试领域&#xff0c;人工智能&#xff08;AI&#xff09;的出现犹如一场技术革命&#xff0c;改变了传统的测试管理方式。随着AI技术的迅速发展&#xff0c;它将如何进一步提升测试管理的效率与准确性&#xff1f;未来的AI驱动测试管理工具又会带来哪些令人期待的创新呢…

unittest | 使用unittest模块来测试logging日志模块功能

我们在这篇文章实现了在项目工程中编写一个logging模块&#xff0c;但是我们如何确定我们编写的模块功能的是否正常? 你可能想到将全部代码写完后运行测试&#xff0c;但这是一个非常不好的习惯。❌ 最好的方式&#xff0c;是每写出来一个功能或者方法就对它进行测试&#x…

MySQL 存储引擎有哪些?InnoDB 和 MyISAM 存储引擎有什么区别?

MySQL 存储引擎有哪些&#xff1f; MySQL 存储引擎主要负责查询的执行和数据的存储&#xff0c;存储引擎主要有 InnoDB&#xff0c;MyISAM&#xff0c;Memery InnoDB 是 MySQL 默认的存储引擎&#xff0c;支持事务和行级锁&#xff0c;以及外键的约束&#xff0c;具有事务提交…

揭秘推荐算法:深度学习如何读懂你的购物心思

时间&#xff1a;2024年09月03日 作者&#xff1a;小蒋聊技术 邮箱&#xff1a;wei_wei10163.com 微信&#xff1a;wei_wei10 音频&#xff1a;https://xima.tv/1_L8HH40?_sonic0 希望大家帮个忙&#xff01;如果大家有工作机会&#xff0c;希望帮小蒋内推一下&#xff0c…

帅地:秋招入职腾讯,后裸辞创业年入百万,一位全职程序员博主的第六年

这是《开发者说》的第17期&#xff0c;这次我们采访的是知名的程序员博主&#xff1a;帅地。 帅地从大学开始接触公众号&#xff0c;在大学毕业时就沉淀了10w垂直粉丝&#xff0c;月入近10w。在秋招阶段&#xff0c;帅地靠扎实的算法基础和技术功底顺利入职腾讯。“还没折腾够”…

【分布式注册中心】NACOS_2.3.0部署与实战

部署 一 准备 1 依赖&#xff1a;MYSQL 2 创建数据库 CREATE database if NOT EXISTS nacos default character set utf8mb4 collate utf8mb4_unicode_ci; 3 导入初始化SQL https://raw.githubusercontent.com/alibaba/nacos/develop/distribution/conf/mysql-schema.sql…

了解Spring Data JPA

1、Spring Data JPA 1.1、概述 Spring Data JPA 是 Spring 基于JPA 规范的基础上封装的⼀套 JPA 应⽤框架&#xff0c;可使开发者⽤极简的代码即可实现对数据库的访问和操作。它提供了包括增删改查等在内的常⽤功能&#xff01;学习并使⽤Spring Data JPA 可以极⼤提⾼开发效率…

cefsharp128_cef128_chromium6613_x64_h264版本抢险体验

一、本博测试版本cef128及兼容性测试 1.1 版本 128.0.6613.x (全网保持最新更新测试体验) 感谢您:关注我,关注栏目,总有您想要的资源,推荐好友有优惠 1.2 兼容性测试,支持h264 1.3 视频播放测试 版本兼容 cef128.xx.xx <

哈希 详解

目录 1. “哈希”是什么&#xff1f; 2. 哈希冲突 3. 哈希函数 3.1 设计原则 3.2 常见哈希函数 4. 解决哈希冲突的两种常见方法 4.1 闭散列 4.2 开散列 4.3 散列表的扩容问题 5. 哈希表的实现 并 封装模拟实现unordered系列容器 6. 哈希的应用 6.1 位图 -- bitset …

vue3+ts项目新建后找不到模块vue或类型{}上不存在属性

新建的项目&#xff0c;不影响功能&#xff0c;但是红色的波浪线很不好看。 在tsconfig.json文件中增加一行代码&#xff1a;让ts识别vue文件 "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue&quo…

特异性心肌细胞靶向肽(PCM);WLSEAGPVVTVRALRGTGSW;CAS:771479-86-8

【特异性心肌细胞靶向肽(PCM) 简介】 特异性心肌细胞靶向肽&#xff08;PCM&#xff09;是一种设计用于识别和结合心肌细胞特有的受体或分子标记的多肽序列。PCM可以通过其氨基酸序列的特定配置和表面特性实现对心肌细胞的选择性靶向&#xff0c;从而在心脏病治疗中递送药物、作…

Idea_服务器自动化部署_傻瓜式教程

使用Alibaba Cloud Toolkit 在 IntelliJ IDEA 中一键部署项目到服务器 1. 安装 Alibaba Cloud Toolkit 插件 确保 IntelliJ IDEA 版本为 2018.3 或以上。打开 IntelliJ IDEA&#xff0c;进入 File -> Settings -> Plugins&#xff0c;搜索并安装 Alibaba Cloud Toolkit…

【重学 MySQL】一、数据库概述

【重学 MySQL】一、数据库概述 为什么要使用数据库数据库与数据库管理系统数据库&#xff08;Database&#xff09;数据库管理系统&#xff08;DBMS&#xff09;数据库与数据库管理系统的关系数据库是数据存储的容器数据库管理系统是数据库的管理者相互依存的关系数据库系统的组…

论斜率优化dp

论斜率优化dp 1问题2暴力算法-线性dp3斜率优化线性dp4后记 1问题 如下图 看到这题&#xff0c;题面很复杂 其实可以转化为如下问题 有 n n n个任务&#xff0c;排成一个有序序列&#xff0c;我们要解决这些任务 总费用是每一个任务的完成时间乘以费用系数求和 每个任务之前…

RAG 进阶:零成本 chat_with_readthedocs

Readthedocs 是知名的文档托管平台&#xff0c;通常用于免费存放 GitHub 和 GitLab 的项目文档。当项目文档较多时&#xff0c;简单的搜索难以满足读者需求&#xff0c;此外在 AI 2.0 时代&#xff0c;“主动寻找答案”这类用户体验已经逐渐落后。 本文将介绍如何基于 Huixian…

4款AI智能改写工具,轻松快速改出优质文章

在当今数字化内容创作的时代&#xff0c;高质量的文章对于个人和企业来说都具有至关重要的意义。然而&#xff0c;有时候我们可能会面临需要对已有文章进行改写的情况&#xff0c;以避免重复、优化语言表达或者适应不同的受众。这时&#xff0c;AI智能改写工具就成为了我们的得…

解决AutoDL远程服务器训练大模型的常见问题:CPU内存不足与 SSH 断开

在使用远程服务器&#xff08;如 AutoDL&#xff09;进行深度学习训练时&#xff0c;通常会遇到一些常见问题&#xff0c;比如由于数据加载导致的内存消耗过高&#xff0c;以及 SSH 连接中断后训练任务被迫停止。这篇文章将介绍我在这些问题上遇到的挑战&#xff0c;并分享相应…

前缀和专题——一维模版+二维模版力扣实战应用

目录 1、模版 1.1【模版】一维前缀和 1.1.1 算法思想 1.1.2 算法代码 1.2【模版】二维前缀和 1.2.1 算法思想 1.2.2 算法代码 2、算法应用【leetcode】 2.1 题一&#xff1a;寻找数组的中心下标 2.1.1 算法思想 2.1.2 算法代码 2.2 题二&#xff1a;除自身以外数组…