vue关于静态路由和动态路由:

news2025/4/17 1:35:22

这篇文章写得超详细!!! 👉vue实现动态路由一步到位_vue动态路由怎么实现_ds_surk的博客-CSDN博客

目录

静态路由的配置:

步骤: 

动态路由的配置:

步骤:

代码实现:

步骤2详解:

步骤3详解:

步骤4详解:

其他问题:


静态路由的配置:

步骤: 

1、router的index.js写几个页面—>2、router的permission.js配置路由导航—>3、入口文件main.js引入这两个文件—>4、APP.vue文件放入路由跳转的视图区

//1.router下index.js文件;有几个简单的页面
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/view/login/Login'
import Index from '@/layout/Index'
import Welcome from '@/layout/welcome/Welcome'
 
Vue.use(Router)
 
export default new Router({
  routes: [
    {
      path: '/login',
      name: 'Login',
      component: Login
    },
    {
      path: '/',
      component: Index,
      redirect: '/welcome',
      meta: {requireAuth: true},
      children: [
        {
          path: '/welcome',
          component: Welcome,
          name: '首页',
          meta: {title: '首页', requireAuth: true}
        }
      ]
    }
  ]
})

//2.router下permission.js文件:配置路由导航,每次路由跳转前做一些操作
import router from '@/router/index'
import 'element-ui/lib/theme-chalk/index.css'
import '@fortawesome/fontawesome-free/css/all.min.css'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
 
NProgress.configure({
  easing: 'ease', // 动画方式
  speed: 500, // 递增进度条的速度
  showSpinner: false, // 是否显示加载ico
  trickleSpeed: 200, // 自动递增间隔
  minimum: 0.3 // 初始化时的最小百分比
})
// 白名单
const whiteList = ['/login'] // no redirect whitelist
 
// 导航守卫
router.beforeEach((to, from, next) => {
  NProgress.start()
  if (to.meta.requireAuth) {
    // 判断该路由是否需要登录权限
    if (sessionStorage.getItem('loginName') !== null) {
      // 判断本地是否存在token
      next()
      // 这里是待会获取异步路由的地方
    } else {
      // 未登录,跳转到登陆页面
      next({
        path: '/login'
      })
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      if (sessionStorage.getItem('loginName') !== null) {
        // 判断本地是否存在token
        next(`/?redirect=${to.path}`)
      } else {
        next(`/login?redirect=${to.path}`)
      }
    }
  }
})
 
router.afterEach(() => {
  // 在即将进入新的页面组件前,关闭掉进度条
  NProgress.done()
})


//3、main.js中引入上面router下的两个文件
import router from '@/router'
import './router/permission'
 
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})


// 4、APP.vue文件放入路由跳转的视图区,跳转的路由页面都显示在这里
<div id="app">
    <router-view />
</div>

动态路由的配置:

步骤:

1、router/index.js,删掉需要动态获取的路由信息,可以留一部分静态路由—>

2、router/getAsyncRouter.js,用来处理获取到的动态路由信息—>

3、用beforeEach,在router/permission.js文件,配置导航守卫,在每次路由跳转前做一些操作,获取动态路由—>

4、写store并将store中的数据存储到本地

        配置动态路由其实就是把静态路由存到数据库,在取出来放进路由表(静态是直接写在路由表里)。

代码实现:

//2、router下getAsyncRouter.js,用来处理获取到的动态路由信息
// 用于处理动态菜单数据,将其转为 route 形式
export function fnAddDynamicMenuRoutes (menuList = [], routes = []) {
  // 用于保存普通路由数据
  let temp = []
  // 用于保存存在子路由的路由数据
  let route = []
  // 遍历数据
  for (let i = 0; i < menuList.length; i++) {
    // 存在子路由,则递归遍历,并返回数据作为 children 保存
    if (menuList[i].children && menuList[i].children.length > 0) {
      // 获取路由的基本格式
      route = getRoute(menuList[i])
      // 递归处理子路由数据,并返回,将其作为路由的 children 保存
      route.children = fnAddDynamicMenuRoutes(menuList[i].children)
      // 保存存在子路由的路由
      routes.push(route)
    } else {
      // 保存普通路由
      temp.push(getRoute(menuList[i]))
    }
  }
  // 返回路由结果
  return routes.concat(temp)
}
 
// 返回路由的基本格式
function getRoute (item) {
  // 路由基本格式
  let route = {
    // 路由的路径
    path: item.url,
    // 路由名
    name: item.name,
    // 路由所在组件
    // component: (resolve) => require([`@/layout/Index`], resolve),
    component: (resolve) => require([`@/view${item.curl}`], resolve),
    meta: {
      id: item.id,
      icon: item.icon
    },
    // 路由的子路由
    children: []
  }
  // 返回 route
  return route
}



//3、有了处理动态路由数据的函数,那就需要在合适的地方调用,以发挥作用。
//这时就需要用到beforeEach了,在router/permission.js文件,
//配置导航守卫,可以在每次路由跳转前做一些操作,这里就是获取动态路由了
import router from '@/router/index'
import 'element-ui/lib/theme-chalk/index.css'
import '@fortawesome/fontawesome-free/css/all.min.css'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {fnAddDynamicMenuRoutes} from '@/router/getAsyncRouter'
import {getRouter} from '@/api/sys/Menu'
import store from '@/store'
 
 
NProgress.configure({
  easing: 'ease', // 动画方式
  speed: 500, // 递增进度条的速度
  showSpinner: false, // 是否显示加载ico
  trickleSpeed: 200, // 自动递增间隔
  minimum: 0.3 // 初始化时的最小百分比
})
// 白名单
const whiteList = ['/login'] // no redirect whitelist
 
// 导航守卫
router.beforeEach((to, from, next) => {
  NProgress.start()
  try {
    // 判断是否已经获取过动态菜单,未获取,则需要获取一次
    if (store.getters.dynamicRoutes.length === 0) {
      if (whiteList.indexOf(to.path) !== -1) {
        next()
      } else {
        getRouter().then(res => {
          if (res.code === 0) {
            let menuRouter = fnAddDynamicMenuRoutes(res.data[0].children)
            store.dispatch('app/dynamicRoutes', menuRouter).then(() => {
              router.addRoutes(store.getters.dynamicRoutes)
              next({...to, replace: true})
            })
          } else {
            console.log('获取动态路由失败!')
            next({path: '/login'})
          }
        })
      }
    } else {
      // 路由已存在或已缓存路由
      if (to.meta.requireAuth) {
        if (sessionStorage.getItem('loginName') !== null) {
          // 判断本地是否存在token
          next()
        } else {
          // 未登录,跳转到登陆页面
          next({path: '/login'})
        }
      } else {
        if (whiteList.indexOf(to.path) !== -1) {
          next()
        } else {
          if (sessionStorage.getItem('loginName') !== null) {
            // 判断本地是否存在token
            next(`/?redirect=${to.path}`)
          } else {
            next(`/login?redirect=${to.path}`)
          }
        }
      }
    }
  } catch (error) {
    console.log('出错了')
    next(`/login?redirect=${to.path}`)
  }
})
 
router.afterEach(() => {
  // 在即将进入新的页面组件前,关闭掉进度条
  NProgress.done()
})
 




//4、store的写法
 
const state = {
  dynamicRoutes: []
}
 
const mutations = {
  DYNAMIC_ROUTES (state, routes) {
    state.dynamicRoutes = routes
  }
}
 
const actions = {
  dynamicRoutes ({commit}, routes) {
    commit('DYNAMIC_ROUTES', routes)
  }
}


//4.1 在app.vue页面刷新时利用sessionStorage存储一下store,防止刷新丢失vuex。
export default {
  name: 'App',
  created () {
    // 在页面加载时读取sessionStorage里的状态信息
    if (sessionStorage.getItem('storeData')) {
      this.$store.replaceState(Object.assign({}, 
       this.$store.state, JSON.parse(sessionStorage.getItem('storeData')
    )))
    }
    // 在页面刷新时将vuex里的信息保存到sessionStorage里
    window.addEventListener('beforeunload', () => {
      sessionStorage.setItem('storeData', JSON.stringify(this.$store.state))
    })
    // 兼容iphone手机
    window.addEventListener('pagehide', () => {
      sessionStorage.setItem('storeData', JSON.stringify(this.$store.state))
    })
  }
}

//4.2在登录成功后也获取了一下动态路由。这样处理下来,刷新时也不会丢失路由了!
// 获取动态路由
getRouter().then(res => {
  if (res.code === 0) {
    let menuRouter = fnAddDynamicMenuRoutes(res.data[0].children)
    store.dispatch('app/dynamicRoutes', menuRouter).then(() => {
      router.addRoutes(store.getters.dynamicRoutes)
    })
    console.log(store.getters.dynamicRoutes)
  } else {
    console.log('获取动态路由失败!')
    router.push('/login')
  }
})

步骤2详解:

这里是两个函数,把获取到的数据处理成路由表数据,将其变化成 route 的形式。

fnAddDynamicMenuRoutes 用于递归菜单数据。
getRoute 用于返回某个数据转换的 路由格式。
注释写的应该算是很详细了,主要讲一下思路:
  对数据进行遍历,
  定义两个数组(temp,route),temp 用于保存没有子路由的路由,route 用于保存存在子路由的路由。
  如果某个数据存在 子路由,则对子路由进行遍历,并将其返回结果作为当前数据的 children。并使用 route 保存路由。
  如果某个数据不存在子路由,则直接使用 temp 保存路由。
  最后,返回两者拼接的结果,即为转换后的数据。
route 格式一般如下:
  path:指路由路径(可以根据路径定位路由)。
  name:指路由名(可以根据路由名定位路由)。
  component:指路由所在的组件。
  children:指的是路由组件中嵌套的子路由。
  meta:用于定义路由的一些元信息。

这里有个大坑!!! 在配置component的时候,需要动态导入组件,也就是vue异步组件,查看文档如下

 可知,有两种导入方式,import和require方式。这里简单说一下,

1 import属于es6导入方式,只支持静态导入,也就是说,你不能够使用变量或表达式,只能使用字符串。

2 require属于commonJS方式,可以支持动态的导入,但笔者尝试中,可以使用``模板字符串方式,貌似也无法直接使用变量。这里尽量用字符串拼接,而不是用变量去代替拼接的字符串!

由于import不支持动态导入方式,笔者采用的是require的方式,并且在webpack文档中有这样一段话。
clipboard.png

综上所述,就是说,组件的导入可以使用字符串拼接的方式导入,可以使用模板字符串导入(字符串中含有变量),但是使用模板字符串导入时不能够只使用变量!!必须指定一个目录,不能全用变量代替! 

// 字符串拼接方式
component: import('@/view'+'/sys/user')
// 模板字符串方式,webpack4+版本需使用require方式,
// 注意,`@${item.curl}`,是不行的!必须指定一个目录,不能全用变量代替
component: (resolve) => require([`@/view${item.curl}`], resolve),

这个现象其实是与webpack import()的实现高度相关的。由于webpack需要将所有import()的模块都进行单独打包,所以在工程打包阶段,webpack会进行依赖收集。

此时,webpack会找到所有import()的调用,将传入的参数处理成一个正则,如:

import('./app'+path+'/util') => /^\.\/app.*\/util$/

也就是说,import参数中的所有变量,都会被替换为【.*】,而webpack就根据这个正则,查找所有符合条件的包,将其作为package进行打包。

所以动态导入的正确姿势,应该是尽可能静态化表达包所处的路径,最小化变量控制的区域

步骤3详解:

注释写的比较详细了,主要说下思路:

首先确定获取动态菜单数据的时机。一般在登录成功跳转到主页面时,获取动态菜单数据。
      由于涉及到路由的跳转(登录页面 -> 主页面),所以可以使用 beforeEach 进行路由导航守卫操作。
      但由于每次路由跳转均会触发 beforeEach ,所以为了防止频繁获取动态路由值,这里采用vuex方式存储了获取的路由信息,如果已获取路由,就直接跳转,否则就获取一次动态菜单数据并处理。

如果不采用vuex方式也可以存到sessionStorage里面,总之就是保存一下获取的路由信息,以免重复获取。
 

步骤4详解:

注意:vue是单页面应用程序,所以页面一刷新数据部分数据也会跟着丢失,所以我们需要将store中的数据存储到本地,才能保证路由不丢失。

        在刷新页面时遇到一个问题,动态路由表会随着vuex的刷新而消失。

        处理:(代码在上面)

        1、这里在app.vue页面刷新时利用sessionStorage存储一下store,防止刷新丢失vuex。

        2、在登录成功后也获取了一下动态路由。这样处理下来,刷新时也不会丢失路由了!

其他问题:

1.首先是component动态导入的问题,由于webpack的版本不同,需要根据情况来采用import和require方式来导入,如果导入不正确多半会报错,找不到module等等。或者不报错,但路由跳转是空白页。如果导入正确则一定可以跳转正常,否则,请查找正确的导入方法!路由跳转正确,能显示跳转的组件,就完成了一大半!

2.路由的跳转的地方,由于我们项目采用的是左侧菜单栏,有二级菜单,所以当路由跳转正常时,还需确定路由跳转所渲染的位置是否正确!


————————————————
版权声明:本文为CSDN博主「ds_surk」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hunt_er/article/details/110661577

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

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

相关文章

网易云音乐开发--search模块基本功能实现(除历史记录模块)

search头部搭建 老样子搭建一个search搜索页面 还有一块没有实现&#xff0c;那就是让输入框默认的文本变换颜色 微信小程序: input输入框placeholder样式的修改_微信小程序placeholder样式_酷伊奥的博客-CSDN博客 百度搜索了一下&#xff0c;找到了这个大佬的解决方案。很nic…

ICV:中国的数字经济与5G市场研究报告

近日&#xff0c;专注于前沿科技领域的国际咨询机构ICV发布了《中国的数字经济与5G市场研究报告》。报告指出&#xff0c;随着5G商用的发展&#xff0c;5G对经济社会的影响逐步显现&#xff0c;其影响突出体现在对数字产业发展的带动上。随着5G应用的不断创新与扩散&#xff0c…

chrome插件打包之后,显示此扩展程序可能已损坏

每日鸡汤&#xff0c;每个你想要学习的瞬间都是未来的你向自己求救 问题是这样的&#xff0c;我们有一个chrome插件的项目&#xff0c;但是我也没有参与开发&#xff0c;可以说此前对chrome插件一窍不通。但是今天呢&#xff0c;有个bug&#xff0c;要我改&#xff0c;我就拉一…

基于Java+SpringBoot+Vue的校园交友网站的设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架下…

为什么x86架构一个字节是8个bit

探究计算机存储的历史&#xff1a;为什么x86架构下一个字节是8个bit 原文链接&#xff1a;Some possible reasons for 8-bit bytes About author I’m a software developer. I live in Montreal. I sometimes give talks. Most of my income comes from my programming zines…

【博览群书】《实战大数据》——属于我的第一本大数据图书

文章目录 前言简介目录其他 前言 Hello家人们&#xff0c;博主前不久参加了CSDN图书馆和机械工业出版社联合举办的图书类活动&#xff0c;很荣幸在活动中获得了属于自己的第一本大数据图书&#xff0c;《实战大数据—— 分布式大数据分析处理系统开发与应用》。作为大数据专业…

五、数据仓库详细介绍(建模)理论篇

1 前言 大家好&#xff0c;本篇文章是数仓详细介绍系列的第四篇。 第一篇是简单介绍&#xff0c;后三篇属于数仓设计部分&#xff1a; 数仓概述&#xff0c;这一篇我给大家简单介绍了数据仓库的基本概念和大致构建过程&#xff0c;没有过多深入主要是给大家有个基本的了解。 数…

数字孪生应用落地,“未来之城”或成智慧城市新形态

“最近&#xff0c;到北京大学人民医院西直门院区就诊的患者发现&#xff1a;动辄绵延数百米的“车龙”消失了&#xff0c;周边道路也变得畅通起来。高峰期排队进院花费的时间&#xff0c;从过去1个多小时减至现在的10分钟左右。 与之相隔不远的北京市西城区城市管理委员会办公…

Java程序设计入门教程--类的行为

类的成员方法是Java描述类对象行为的途径。成员方法的定义应包含两部分内容&#xff1a;方法声明和方法体。 方法定义常用的格式如下&#xff1a; [public/protected/private][static][final/abstract] returnType methodName([param List]) [throw…

ER图和数据库模型图怎么使用呢?

1. 简介 对于从事数据库结构设计相关人员而言&#xff0c;我们通常会在设计的不同阶段用到ER图和数据库模型图&#xff0c;用来描述数据之间的组成结构和数据间的关系&#xff0c;但是很多画图人员会把它们两者给搞混了&#xff0c;下面就来聊聊它们之间的区别。 1、ER图全称…

【TES600】基于XC7K325T与TMS320C6678的通用信号处理平台

板卡概述 TES600是一款基于FPGA&#xff0b;DSP协同处理架构的通用高性能实时信号处理平台&#xff0c;该平台采用1片TI的KeyStone系列多核浮点/定点DSP TMS320C6678作为主处理单元&#xff0c;采用1片Xilinx的Kintex-7系列FPGA XC7K325T作为协处理单元&#xff0c;具有1个FMC子…

XML配置方式SSM框架西蒙购物网

文章目录 一、网站功能需求二、网站设计思路&#xff08;一&#xff09;设计模式&#xff08;二&#xff09;网站前台&#xff08;三&#xff09;网站后台1、用户管理2、类别管理3、商品管理4、订单管理 &#xff08;四&#xff09;购物流程图 三、网站运行效果四、网站实现步骤…

大一新生如何自学JavaScript?

前言 针对于题主的情况&#xff0c;我特意做了一份Js方面的知识路线图以及一些知识点讲解的资源链接&#xff0c;希望对于还未学习Js或者已经学习了Js但没有但没有一个系统路线的小伙伴能有一些帮助~ 先放上路线图 img 部分重要知识点 基础性知识 声明变量 null 和 undefi…

二总线-MBus讲解

二总线的叫法演变是从多线到总线再到二总线这么一个过程&#xff0c;尤其在楼宇的消防领域&#xff0c;报警的设备总线基本已经是二总线了&#xff0c;其特点就是电源与通信一起传输&#xff0c;本质上是一个电力载波的思路。那么现在的powerbus二总线又是一个极端&#xff0c;…

chatgpt赋能Python-python_judge

Python Judge&#xff1a;一个高效的Python代码评测平台 如果你是一个Python程序员或是教师&#xff0c;你一定需要测试你的Python代码表现。Python Judge是一个专门为Python程序员设计的代码评测平台&#xff0c;它可以帮助你测试你的Python代码的运行时间、空间占用和准确性…

DDD在前端应用中的一些思考

作者&#xff1a;吴尔畅 DDD旨在解决业务逻辑的复杂性&#xff0c;而业务逻辑大部分场景下不存在于前端。但在一些复杂的应用中&#xff0c;前端可能需要处理一些业务逻辑&#xff0c;此时DDD的一些思想和方法可能有助于组织前端代码&#xff0c;使其更易于理解和维护。 一、什…

【STL模版库】list介绍及使用 {inserterase的迭代器失效问题,vector_sort VS list_sort,list的其他接口函数}

一、list的介绍 list是可以在常数时间内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。list的底层是双向带头循环链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其前一个元素和后一个元…

JavaEE(系列10) -- 多线程案例3(定时器)

目录 1. 定时器 2. 标准库中的定时器 3. 实现定时器 3.1 创建带优先级的阻塞队列 3.2 创建MyTask类 3.3 构建schedule方法 3.4 构建timer类中的线程 3.5 思考 1. 定时器 定时器也是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某…

chatgpt赋能Python-python_gauge

Python Gauge: 新一代的测试工具 Python Gauge是一个用于自动化测试的轻量级框架&#xff0c;它具有可扩展性和适应性&#xff0c;特别适合测试大型应用程序。Python Gauge支持多种编程语言包括Python&#xff0c;Java&#xff0c;C#和Ruby&#xff0c;因此可以应对各种情况。…

燃气管网监测系统:解析地下管道安全隐患

地下燃气管道是现代城市能源供应的重要组成部分&#xff0c;它们为居民和工业提供了安全、便利的燃气能源。然而&#xff0c;随着时间的推移&#xff0c;地下燃气管道可能出现安全隐患&#xff0c;如老化、腐蚀、机械损伤等&#xff0c;这可能导致泄漏、爆炸和环境污染等严重后…