0

0

权限管理模块中动态加载Vue组件实例详解

小云云

小云云

发布时间:2018-01-16 17:09:31

|

2198人浏览过

|

来源于php中文网

原创

本系列文章并不是手把手的教程,主要介绍了核心思路并讲解了核心代码,完整的代码小伙伴们可以在github上star并clone下来研究。另外,原本计划把项目跑起来放到网上供小伙伴们查看,但是之前买服务器为了省钱,内存只有512m,两个应用跑不起来(已经有一个v部落开源项目在运行),因此小伙伴们只能将就看一下下面的截图了,github上有部署教程,部署到本地也可以查看完整效果。


项目地址:https://github.com/lenve/vhr

前面几篇文章,我们已经基本解决了服务端的问题,并封装了前端请求,本文我们主要来聊聊登录以及组件的动态加载。

本文是本系列的第五篇,建议先阅读前面的文章有助于更好的理解本文:

1.SpringBoot+Vue前后端分离,使用SpringSecurity完美处理权限问题(一)  
2.SpringBoot+Vue前后端分离,使用SpringSecurity完美处理权限问题(二)  
3.SpringSecurity中密码加盐与SpringBoot中异常统一处理  
4.axios请求封装和异常统一处理

立即学习前端免费学习笔记(深入)”;

登录状态保存

当用户登录成功之后,需要将当前用户的登录信息保存在本地,方便后面使用。具体实现如下:

登录成功保存数据

在登录操作执行成功之后,通过commit操作将数据提交到store中,核心代码如下:

<span style="font-size: 14px;">this.postRequest('/login', {<br/>    username: this.loginForm.username,<br/>    password: this.loginForm.password<br/>}).then(resp=> {<br/>    if (resp && resp.status == 200) {<br/>    var data = resp.data;<br/>    _this.$store.commit('login', data.msg);<br/>    var path = _this.$route.query.redirect;<br/>    _this.$router.replace({path: path == '/' || path == undefined ? '/home' : path});<br/>    }<br/>});<br/></span>

store

store的核心代码如下:

<span style="font-size: 14px;">export default new Vuex.Store({<br/>  state: {<br/>    user: {<br/>      name: window.localStorage.getItem('user' || '[]') == null ? '未登录' : JSON.parse(window.localStorage.getItem('user' || '[]')).name,<br/>      userface: window.localStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.localStorage.getItem('user' || '[]')).userface<br/>    }<br/>  },<br/>  mutations: {<br/>    login(state, user){<br/>      state.user = user;<br/>      window.localStorage.setItem('user', JSON.stringify(user));<br/>    },<br/>    logout(state){<br/>      window.localStorage.removeItem('user');<br/>    }<br/>  }<br/>});<br/></span>

为了减少麻烦,用户登录成功后的数据将被保存在localStorage中(防止用户按F5刷新之后数据丢失),以字符串的形式存入,取的时候再转为json。当用户注销登陆时,将localStorage中的数据清除。

组件动态加载

在权限管理模块中,这算是前端的核心了。

核心思路

用户在登录成功之后,进入home主页之前,向服务端发送请求,要求获取当前的菜单信息和组件信息,服务端根据当前用户所具备的角色,以及角色所对应的资源,返回一个json字符串,格式如下:

<span style="font-size: 14px;">[<br/>    {<br/>        "id": 2,<br/>        "path": "/home",<br/>        "component": "Home",<br/>        "name": "员工资料",<br/>        "iconCls": "fa fa-user-circle-o",<br/>        "children": [<br/>            {<br/>                "id": null,<br/>                "path": "/emp/basic",<br/>                "component": "EmpBasic",<br/>                "name": "基本资料",<br/>                "iconCls": null,<br/>                "children": [],<br/>                "meta": {<br/>                    "keepAlive": false,<br/>                    "requireAuth": true<br/>                }<br/>            },<br/>            {<br/>                "id": null,<br/>                "path": "/emp/adv",<br/>                "component": "EmpAdv",<br/>                "name": "高级资料",<br/>                "iconCls": null,<br/>                "children": [],<br/>                "meta": {<br/>                    "keepAlive": false,<br/>                    "requireAuth": true<br/>                }<br/>            }<br/>        ],<br/>        "meta": {<br/>            "keepAlive": false,<br/>            "requireAuth": true<br/>        }<br/>    }<br/>]<br/></span>

前端在拿到这个字符串之后,做两件事:1.将json动态添加到当前路由中;2.将数据保存到store中,然后各页面根据store中的数据来渲染菜单。

核心思路并不难,下面我们来看看实现步骤。

数据请求时机

这个很重要。

聚好用AI
聚好用AI

可免费AI绘图、AI音乐、AI视频创作,聚集全球顶级AI,一站式创意平台

下载

可能会有小伙伴说这有何难,登录成功之后请求不就可以了吗?是的,登录成功之后,请求菜单资源是可以的,请求到之后,我们将之保存在store中,以便下一次使用,但是这样又会有另外一个问题,假如用户登录成功之后,点击某一个子页面,进入到子页面中,然后按了一下F5进行刷新,这个时候就GG了,因为F5刷新之后store中的数据就没了,而我们又只在登录成功的时候请求了一次菜单资源,要解决这个问题,有两种思路:1.将菜单资源不要保存到store中,而是保存到localStorage中,这样即使F5刷新之后数据还在;2.直接在每一个页面的mounted方法中,都去加载一次菜单资源。

由于菜单资源是非常敏感的,因此最好不要不要将其保存到本地,故舍弃方案1,但是方案2的工作量有点大,因此我采取办法将之简化,采取的办法就是使用路由中的导航守卫。

路由导航守卫

我的具体实现是这样的,首先在store中创建一个routes数组,这是一个空数组,然后开启路由全局守卫,如下:

<span style="font-size: 14px;">router.beforeEach((to, from, next)=> {<br/>    if (to.name == 'Login') {<br/>      next();<br/>      return;<br/>    }<br/>    var name = store.state.user.name;<br/>    if (name == '未登录') {<br/>      if (to.meta.requireAuth || to.name == null) {<br/>        next({path: '/', query: {redirect: to.path}})<br/>      } else {<br/>        next();<br/>      }<br/>    } else {<br/>      initMenu(router, store);<br/>      next();<br/>    }<br/>  }<br/>)<br/></span>

这里的代码很短,我来做一个简单的解释:  
1.如果要去的页面是登录页面,这个没啥好说的,直接过。

2.如果不是登录页面的话,我先从store中获取当前的登录状态,如果未登录,则通过路由中meta属性的requireAuth属性判断要去的页面是否需要登录,如果需要登录,则跳回登录页面,同时将要去的页面的path作为参数传给登录页面,以便在登录成功之后跳转到目标页面,如果不需要登录,则直接过(事实上,本项目中只有Login页面不需要登录);如果已经登录了,则先初始化菜单,再跳转。

初始化菜单的操作如下:

<span style="font-size: 14px;">export const initMenu = (router, store)=> {<br/>  if (store.state.routes.length > 0) {<br/>    return;<br/>  }<br/>  getRequest("/config/sysmenu").then(resp=> {<br/>    if (resp && resp.status == 200) {<br/>      var fmtRoutes = formatRoutes(resp.data);<br/>      router.addRoutes(fmtRoutes);<br/>      store.commit('initMenu', fmtRoutes);<br/>    }<br/>  })<br/>}<br/>export const formatRoutes = (routes)=> {<br/>  let fmRoutes = [];<br/>  routes.forEach(router=> {<br/>    let {<br/>      path,<br/>      component,<br/>      name,<br/>      meta,<br/>      iconCls,<br/>      children<br/>    } = router;<br/>    if (children && children instanceof Array) {<br/>      children = formatRoutes(children);<br/>    }<br/>    let fmRouter = {<br/>      path: path,<br/>      component(resolve){<br/>        if (component.startsWith("Home")) {<br/>          require(['../components/' + component + '.vue'], resolve)<br/>        } else if (component.startsWith("Emp")) {<br/>          require(['../components/emp/' + component + '.vue'], resolve)<br/>        } else if (component.startsWith("Per")) {<br/>          require(['../components/personnel/' + component + '.vue'], resolve)<br/>        } else if (component.startsWith("Sal")) {<br/>          require(['../components/salary/' + component + '.vue'], resolve)<br/>        } else if (component.startsWith("Sta")) {<br/>          require(['../components/statistics/' + component + '.vue'], resolve)<br/>        } else if (component.startsWith("Sys")) {<br/>          require(['../components/system/' + component + '.vue'], resolve)<br/>        }<br/>      },<br/>      name: name,<br/>      iconCls: iconCls,<br/>      meta: meta,<br/>      children: children<br/>    };<br/>    fmRoutes.push(fmRouter);<br/>  })<br/>  return fmRoutes;<br/>}<br/></span>

在初始化菜单中,首先判断store中的数据是否存在,如果存在,说明这次跳转是正常的跳转,而不是用户按F5或者直接在地址栏输入某个地址进入的。否则就去加载菜单。拿到菜单之后,首先通过formatRoutes方法将服务器返回的json转为router需要的格式,这里主要是转component,因为服务端返回的component是一个字符串,而router中需要的却是一个组件,因此我们在formatRoutes方法中动态的加载需要的组件即可。数据格式准备成功之后,一方面将数据存到store中,另一方面利用路由中的addRoutes方法将之动态添加到路由中。

菜单渲染

最后,在Home页中,从store中获取菜单json,渲染成菜单即可,相关代码可以在<span style="font-size: 14px;">Home.vue</span>中查看,不赘述。

OK,如此之后,不同用户登录成功之后就可以看到不同的菜单了。

相关推荐:

vue组件之Alert详解

jquery加载单文件vue组件方法分享

实例详解vue组件父子间通信之聊天室


热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

457

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

549

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

337

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

82

2025.09.10

jquery插件有哪些
jquery插件有哪些

jquery插件有jQuery UI、jQuery Validate、jQuery DataTables、jQuery Slick、jQuery LazyLoad、jQuery Countdown、jQuery Lightbox、jQuery FullCalendar、jQuery Chosen和jQuery EasyUI等。本专题为大家提供jquery插件相关的文章、下载、课程内容,供大家免费下载体验。

156

2023.09.12

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

337

2023.10.13

jquery删除元素的方法
jquery删除元素的方法

jquery可以通过.remove() 方法、 .detach() 方法、.empty() 方法、.unwrap() 方法、.replaceWith() 方法、.html('') 方法和.hide() 方法来删除元素。更多关于jquery相关的问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

406

2023.11.10

jQuery hover()方法的使用
jQuery hover()方法的使用

hover()是jQuery中一个常用的方法,它用于绑定两个事件处理函数,这两个函数将在鼠标指针进入和离开匹配的元素时执行。想了解更多hover()的相关内容,可以阅读本专题下面的文章。

515

2023.12.04

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

49

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
nginx浅谈
nginx浅谈

共15课时 | 0.9万人学习

前端开发(基础+实战项目合集)
前端开发(基础+实战项目合集)

共60课时 | 4.4万人学习

第十九期_前端开发
第十九期_前端开发

共111课时 | 14.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号