获取用户信息

我们把 loginget_user_info两件事分开处理,我们在守卫路由中获取路由信息。

router.beforeEach((to, from, next) => {if (!(store.getters.savestate === 0)) {Message({showClose: true,message: '正在编辑状态中,请先保存',type: 'error'})next(false)return}NProgress.start()// 如果已经获取了tokenif (getToken()) {// 如果将要跳转到的页面是/loginif (to.path === '/login') {// 那么就直接调转到/next({ path: '/' })// 进度条结束NProgress.done() // if current page is dashboard will not trigger   afterEach hook, so manually handle it} else {// 如果角色长度为零,即没有获取到角色// 判断当前用户是否已拉取完user_info信息if (store.getters.roles.length === 0) {// 调用action派遣事件发送请求获取用户信息(包括角色权限)。store.dispatch('GetInfo').then(res => { // 拉取用户信息// const roles = res.data.rolesconsole.log('菜单树信息为:', res.data)var { admdivcode, admdivname, year, name, businessNb, officename } = res.data// 以后接口字段待调整。businessNb = '001财政局非税'var userInfo = { admdivcode, admdivname, year, name, businessNb, officename }store.dispatch('SetUserInfo', userInfo)store.dispatch('SetAllUserInfo', res.data.userinfo)store.dispatch('GenerateRoutes', res.data).then(() => { // 生成可访问的路由表router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表next({ ...to, replace: true })// hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record})}).catch((err) => {// getInfo的api报错时,打印错误并返回根目录。store.dispatch('FedLogOut').then(() => {Message.error(err || 'Verification failed, please login again')next({ path: '/' })})})} else {// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓if (hasPermission(store.getters.roles, to.meta.roles)) {next()} else {next({ path: '/401', replace: true, query: { noGoBack: true }})}// 可删 ↑}}} else {// 如果没有获取到token,但是要跳转的页面在白名单中。if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入next()} else {// 如果没有获取到token,且要跳转的页面不在白名单中。// next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页,且记住之前的页面。next(`/login`) // 否则全部重定向到登录页,且记住之前的页面。NProgress.done()}}
})

后台数据库存储的资源(菜单)信息

上图中 ,资源编码(如 zcgl_wjgl)等是构成前端页面路由的基础。

我们会从后端/user/info 获取用户信息:返回的结构结构如下:

{"code": "200","data": {"userShortcut": [],"year": "2019","roles": ["admin"],"admdivcode": "420000","menutree": [.....],"version": "2020","oldYear": false,"admdivname": "省本级","officename": "**局","name": "**","setid": "1234","officecode": "80","usercode": "8043","userinfo": {"passwordquestion": null,"nid": "DCBFA88EF11C4D7AB2DD56AD06C9688B","oid": "80","cid": null,"guid": "DCBFA88EF11C4D7AB2DD56AD06C9688B","year": "2019","admdivcode": "420000","pername": "**",......"clientType": "1","admdivname": "省本级","officename": "**局","officecode": "80","ishall": null,"mack": "2020","setid": "1234"},"username": "**"}
}

其中,形成菜单的节点为:

     "menutree": [{},{"id": "402880b3348289190134835596f700ec","text": "政策法规管理","state": null,"checked": false,"attributes": {},"children": [{"id": "402880b33482891901348355d21c00ee","text": "政策法规文件管理","state": null,"checked": false,"attributes": {"butns": ["/zcfggl/zcfgwjgl/add", "/zcfggl/zcfgwjgl/delete", "/zcfggl/zcfgwjgl/update", "/zcfggl/zcfgwjgl/upload", "/zcfggl/zcfgwjgl/download", "/zcfggl/zcfgwjgl/print", "/zcfggl/zcfgwjgl/set", "/zcfggl/zcfgwjgl/export"]},"children": [],"parentId": "402880b3348289190134835596f700ec","hasParent": true,"hasChildren": false,"icon": "i-zcfgwjgl","btn": false,"menuId": "/zcfggl/zcfgwjgl","levelnum": 0}, {"id": "402880b334828919013483561add00f0","text": "政策法规文件查询","state": null,"checked": false,"attributes": {"butns": ["/zcfggl/zcfgwjcx/print", "/zcfggl/zcfgwjcx/set", "/zcfggl/zcfgwjcx/export"]},"children": [],"parentId": "402880b3348289190134835596f700ec","hasParent": true,"hasChildren": false,"icon": "i-zcfgwjcx","btn": false,"menuId": "/zcfggl/zcfgwjcx","levelnum": 0}, {"id": "402880b334828919013483565ff500f2","text": "非税收入项目库查询","state": null,"checked": false,"attributes": {"butns": ["/zcfggl/fssrxmkcx/print", "/zcfggl/fssrxmkcx/set", "/zcfggl/fssrxmkcx/export"]},"children": [],"parentId": "402880b3348289190134835596f700ec","hasParent": true,"hasChildren": false,"icon": "i-fssrxmkcx","btn": false,"menuId": "/zcfggl/fssrxmkcx","levelnum": 0}, {"id": "402880b33482891901348357ddab00f6","text": "单位非税收入项目查询","state": null,"checked": false,"attributes": {"butns": ["/zcfggl/dwfssrxmcx/print", "/zcfggl/dwfssrxmcx/set", "/zcfggl/dwfssrxmcx/export"]},"children": [],"parentId": "402880b3348289190134835596f700ec","hasParent": true,"hasChildren": false,"icon": "i-dwfssrxmcx","btn": false,"menuId": "/zcfggl/dwfssrxmcx","levelnum": 0}],"parentId": "-1","hasParent": false,"hasChildren": true,"icon": "i-zcfggl","btn": false,"menuId": "/zcfggl","levelnum": 0},......{}],

前端根据后台泛返回的数据,构建前端菜单与路由(主要根据类似"menuId": "/zcfggl/zcfgwjgl"的节点)

router:

本段涉及:什么是路由,路由的使用步骤 动态路由  路由懒加载

路由是根据不同的 url 地址展示不同的内容或页面。

要使用router,必须先搞个路由地图。

静态路由:

1、定义组件

    const Foo = {template:'<div>foo</div>'};const Bar = {template:'<div>bar</div>'}   

2、定义路由地图

const routes = [{path:'/foo',component:Foo,},{path:'/bar',component:Bar}];

3、根据路由地图创建路由实例:

const router = new VueRouter({routes:routes//可以简写 routes:routes})

4、路由实例注入到根实例:

    const app = new Vue({router}).$mount('#app')

5、 整个应用都具有路由功能,项目可以根据自己创建的路由,导航到到不同的页面

<div id="app"><h1>hello app</h1><p><!-- 使用router-link组件来导航 --><router-link to="/foo">Go to Foo</router-link><router-link to="/bar">Go to Bar</router-link></p><!-- 路由出口路由匹配到的在这里--><router-view></router-view></div>

总结一下:route 是一条路由,routes 是一组路由,router是一个机制,相当于管理者,他来管理路由

通过注入路由器,我们可以在任何组件内通过 this.$router 访问路由器,也可以通过 this.$route 访问当前路由.

官方文档通篇都常使用 router 实例。留意一下 this.$router 和 router 使用起来完全一样。我们使用 this.$router 的原因是我们并不想在每个独立需要封装路由的组件中都导入路由。

路由的编程式导航:

静态方式下,使用router-link组件来导航,router-link根据“导航地图”,“渲染”相应router-view。

编程式导航,就是用router.push(...)代替rout-link组件,事实上,router-link其实调用的就是router.push(...)方法。

嵌套路由

实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件.

从main.js中,可见,最外层是#app

import Vue from 'vue'
import App from './App'
......new Vue({el: '#app',router,store,render: h => h(App)
})

app.vue如下:

<template><div id="app"><!-- <div class="main-app">123</div> --><router-view/></div>
</template>
<script>
export default {name: 'App',data() {return {}}
}
</script>

从router中可见到,"/"即为Layout:

//路由
{path: '/',component: Layout,redirect: '/dashboard',name: 'Dashboard',hidden: true,children: [{path: 'dashboard',component: () => import('@/views/dashboard/index')}]
}

Layout.vue结构如下:

<template><div :class="classObj" class="app-wrapper"><div v-if="disabled" class="shield" /><div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /><head-top/><sidebar class="sidebar-container" /><div class="main-container"><navbar class="toggle-sidebar" /><app-main/></div><foot/></div>
</template><script>
import { Navbar, Sidebar, AppMain } from './components'
import HeadTop from '@/components/headTop'
import Foot from '@/components/foot'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
import Bus from '@/utils/Bus'
import { getCodeLabelDictionary } from '@/api/CommonApi'
import { getNowDate } from '@/api/login'export default {name: 'Layout',components: {Navbar,Sidebar,AppMain,HeadTop,Foot},mixins: [ResizeMixin],computed: {...},watch: {...},created() {...},methods: {...}
}
</script>
<style lang="scss">...
</style>

Layout.vue当中,可以看出,有左侧导航栏的区域了。

我们是动态路由和静态路由混用的:

import Vue from 'vue'
import Router from 'vue-router'Vue.use(Router)/* Layout */
import Layout from '../views/layout/Layout'//静态路由部分
export const constantRouterMap = [{path: '/login',component: () => import(`@/views/login/index`),hidden: true
},
{path: '/404',component: () => import('@/views/404'),hidden: true
},
{path: '/',component: Layout,redirect: '/dashboard',name: 'Dashboard',hidden: true,children: [{path: 'dashboard',component: () => import('@/views/dashboard/index')}]
}
]export default new Router({// mode: 'history', //后端支持可开scrollBehavior: () => ({y: 0}),routes: constantRouterMap
})// 异步挂载的路由
// 动态需要根据权限加载的路由表
export const asyncRouterMap = [
]// component: () => import('@/components/permision'),

参考1:vue-router八个重要知识点应用图解

参考2:vue-router 基本使用

参考3:vue-router 快速入门

ps:嵌套路由与路由参数的比较,我前端同事给的解释如下:

嵌套路由的表现形式在url上是这样的 :   /path/pathtwo/paththree
路由参数在url上表现出是这样的: /path/pathtwo/paththree/154/887,这种形式需要在路由的path配置的时候写成 /path/pathtwo/paththree/:appid/:productid
或者以查询字符串形式带问号的那种:/path/pathtwo/paththree?appid=154&productid=887

如果路由参数以非查询字符串形式表示,确实可能和嵌套路由表现出的地址一样 。但是两者在路由router中的path是完全不一样的 。

如 /path/:paramsone/:paramstwo   ,结果paramsone的值为'pathtwo' ,paramstwo  的值为paththree' ,那么最终的路由地址是
 /path/pathtwo/paththree,
而如果此时你正好也写了一个子路由,path为  :/path/pathtwo/paththree

这两个url看起来一样 ,但是匹配的path和组件页面是完全不一样的 。前者匹配的是/path对应的页面 ,后面的paramsone,paramstwo  只不过是路由里面的参数 。
后者匹配的就是/path/pathtwo/paththree对应的页面 ,且无路由参数 。

参考:vue-router+vuex实现加载动态路由和菜单

1、路由 什么时候 什么地方从后端请求的

permission.js中有个守护路由router.beforeEach方法,是取得路由的核心代码。

ps:Promise vs  permission:

Promise:a declaration or assurance that one will do a particular thing or that a particular thing will happen.es6中,用这个词表示是异步函数。

permission:consent; authorization.。

改进点:

后端返回的是该用户可访问的全部菜单 ,并不是全部页面的菜单。
已经与用户绑定了,所以这里的权限过滤并没有起效 。
而且,后端并没有根据用户不同配置不同的角色状态,只是写死了每个登陆的用户都是admin,所以这里的else里永远不会触发,也就是这里的权限过滤还是没有使用。

这种方式是不是值得商榷呢?

2、登录跳转

验证成功就直接跳转首页,跳转的过程,就会触发Navigation Guards,Navigation Guards中,除了验证用户是否登录外,如果是首次登录,还会从后端查询用户的功能菜单,组装成前端的router.

3、路由和左边文件夹导航

如何和左边导航栏关联

导航菜单

通过注入路由器,我们可以在任何组件内通过 this.$router 访问路由器,也可以通过 this.$route 访问当前路由.

官方文档通篇都常使用 router 实例。留意一下 this.$router 和 router 使用起来完全一样。我们使用 this.$router 的原因是我们并不想在每个独立需要封装路由的组件中都导入路由。

主页面布局:

布局层次示意图:

(单页面布局示意图)

Layout的template:

AppMain.vue  右边的视图窗口

appmain 中,有router-view class="view"

element-ui菜单menu:

它有四个

  1. el-menu
  2. el-submenu
  3. el-menu-item-group
  4. el-menu-item

这里el-menu定义了当前的导航菜单及属性,
el-submenu定义了子菜单栏
el-menu-item-group定义了菜单分组   我们项目暂时没用这个
el-menu-item  定义菜单项目

和router 结合,进行动态路由跳转有二种方式:

方式一:在<el-menu>里加上router属性的方式,官网描述如下:

这样就很方便,只要你<el-menu-item>里的index属性值正确就可以直接跳转了,不用再写js方法了

要理解这个element-ui  与router 形成的菜单,先看一个静态的例子:

<el-menu  router :default-active="$route.path" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" theme="dark">  <el-submenu index="1">  <template slot="title">  <i class="el-icon-location"></i>  <span>用户信息</span>  </template>  <el-menu-item-group>  <el-menu-item index="/user/account">账号信息</el-menu-item>  <el-menu-item index="/user/password">修改密码</el-menu-item>  </el-submenu>  <el-submenu index="2">  <template slot="title">  <i class="el-icon-location"></i>  <span>公司信息</span>  </template>  <el-menu-item-group>  <el-menu-item index="/company/userManager">用户管理</el-menu-item>  <el-menu-item index="/company/editUser">添加/编辑用户</el-menu-item>  </el-menu-item-group>  </el-submenu>
</el-menu>

1.要实现路由跳转,先要在el-menu标签上添加router属性,然后只要在每个el-menu-item标签内的index属性设置一下url即可实现点击el-menu-item实现路由跳转。

2.导航当前项,在el-menu标签中绑定  :default-active="$route.path",注意是绑定属性,不要忘了加“:”,当$route.path等于el-menu-item标签中的index属性值时则该item为当前项。

方式二 利用link  或者 点击事件,进行路由跳转:

我们是采取这个思路解决问题。

<template><el-scrollbar wrap-class="scrollbar-wrapper"><el-menu :show-timeout="200" :default-active="$route.path" :collapse="isCollapse" :background-color="variables.menuBg" :text-color="variables.menuText" :active-text-color="variables.menuActiveText" unique-opened mode="vertical"><sidebar-item v-for="route in permission_routers" :key="route.path" :item="route" :base-path="route.path" /></el-menu></el-scrollbar>
</template>

这里,我们看到el-menu没有router的属性了。sidebar-item 是我们自定义的一个组件。

<template><div v-if="!item.hidden&&item.children" class="menu-wrapper">
<!--如果是末级菜单,可以直接链接--><template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"><app-link :to="resolvePath(onlyOneChild.path)"><el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"><item v-if="onlyOneChild.meta" :icon="onlyOneChild.meta.icon||item.meta.icon" :title="onlyOneChild.meta.title" /></el-menu-item></app-link></template>
<!--如果是非末级菜单的情况--><el-submenu v-else :index="resolvePath(item.path)">.......</el-submenu></div></template><script>
import path from 'path'
import { isExternal } from '@/utils/validate'
import Item from './Item'
import AppLink from './Link'export default {name: 'SidebarItem',components: { Item, AppLink },props: {item: {type: Object,required: true},isNest: {type: Boolean,default: false},basePath: {type: String,default: ''}},data() {return {onlyOneChild: null}},methods: {hasOneShowingChild(children, parent) {.......},resolvePath(routePath) {if (this.isExternalLink(routePath)) {return routePath}return path.resolve(this.basePath, routePath)},isExternalLink(routePath) {return isExternal(routePath)}}
}
</script>
<style rel='stylesheet/scss' lang='scss' scoped>
......
</style>

AppLink是我们自定义的一个带插槽的组件。插入的当然是menu_item.

ps:vue 利用component组件和is属性实现动态组件

vue element UI 学习总结笔记(九)_ 导航菜单与路由相关推荐

  1. vue + element ui 的后台管理系统框架_从零开始搭建 VUE + Element UI后台管理系统框架...

    点击右上方红色按钮关注"web秀",让你真正秀起来 前言 后台管理系统前端框架,现在很流行的形式都是,上方和左侧都是导航菜单,中间是具体的内容.比如阿里云.七牛云.头条号.百家号等 ...

  2. 【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Table表格增删查改、Pagination分页、搜索框

    文章目录 目标 代码 0.结构 1.按钮-删除 2.按钮-编辑 3.debug 4.样式 5.分页Pagination:功能 6.分页Pagination:样式 7.搜索框:功能 8.搜索框:样式 总 ...

  3. 【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Form表单填写、Dialog对话框弹出

    文章目录 目标 代码 0.页面结构 1.新增按钮和弹出表单:结构 2.新增按钮和弹出表单:点击新增弹出表单 3.表单样式 4.表单验证 5.表单的提交和取消功能:接口.mock相关准备 6.表单的提交 ...

  4. 【前端】Vue+Element UI案例:通用后台管理系统-登陆不同用户显示不同菜单、动态添加路由

    文章目录 目标 代码 0.动态地显示菜单:store 1.动态注册路由 2.解决刷新后摆平问题 总代码 本篇修改的代码文件 tab.js 参考视频: VUE项目,VUE项目实战,vue后台管理系统,前 ...

  5. 【前端】Vue+Element UI案例:通用后台管理系统-代码总结(已开源)

    文章目录 前言 项目文件目录 api mockServe home.js permission.js index.js mock.js user.js assert components Common ...

  6. nodeJs + webpack+vue+ element ui 环境安装

    一.安装nodeJs 1.打开NodeJs官网:https://nodejs.org/en/download/  点击下载 2.双击安装,安装过程基本直接"NEXT"就可以了.(w ...

  7. 【Vue 快速入门】从零开始搭建 VUE + Element UI后台管理系统框架

    [Vue 快速入门]从零开始搭建 VUE + Element UI后台管理系统框架 前言 后台管理系统前端框架,现在很流行的形式都是,上方和左侧都是导航菜单,中间是具体的内容.比如阿里云.七牛云.头条 ...

  8. 基于vue(element ui) + ssm + shiro 的权限框架

    zhcc 基于vue(element ui) + ssm + shiro 的权限框架 引言 心声 现在的Java世界,各种资源很丰富,不得不说,从分布式,服务化,orm,再到前端控制,权限等等玲琅满目 ...

  9. Element UI学习记录之布局

    目录 Element UI学习记录之布局 一.Layout布局 二.Container布局容器 Element UI学习记录之布局 一.Layout布局 基本概念:一行通过分割为24栅格栏进行布局,如 ...

最新文章

  1. Ubuntu12.04 安装 mongodb
  2. ITK:KMeans聚类
  3. 撩课-Python-每天5道面试题-第2天
  4. Linux下Vim工具常用命令
  5. 《Essential C++》笔记之迭代器Iterator(泛型指针)
  6. Lua笔记2 变量、循环和流程控制
  7. 李子奈《计量经济学》第四版笔记和课后答案
  8. 树莓派摄像头模块(Pi Cam)的安装使用
  9. python爬虫-《笔趣看》网小说《悟空看私聊》
  10. “FCoE全解系列”之网络融合交换机类型
  11. Win10 x64 安装Eplan P8 2.7 小结
  12. MySQL中的极限值
  13. 操作系统期末复习-第一章:操作系统概论
  14. 利用GPS北斗卫星信号开发设计NTP网络时间服务器
  15. 单目-线激光三维扫描系统中光刀平面的标定
  16. 基于C++6.0的Gh0st远控源码研究及在VS2019下的编译修正和测试
  17. 淘宝逛逛,一个0成本适合新手的副业项目
  18. 子豪兄教你从零开始实现人脸识别
  19. 64位百度云 catia v6_CATIA V6R2015百度云
  20. window编译最新的spiderMonkey

热门文章

  1. 众里寻他千百度 哪家单位让你再见如初?这里上市公司、股份集团任你选 | 大数据周聘汇
  2. 手机配合termux部署DDbot 教程
  3. vb sendmessage 详解1
  4. [2021.07.12]Android系统广播机制(Broadcast Receiver)
  5. 使用python画等边三角形的程序-运用Python的turtle库绘制等边三角形
  6. 抖音引流创业容易被人收割的地方
  7. 产品设计培训个人总结
  8. php do while(),php do while用法详解
  9. ZT:“再看OA”系列讲座之三:反思档案管理
  10. Shellcode免杀,绕过360安全卫士、火绒安全、腾讯管家