vue实现用户动态权限登录的代码示例
更新时间:2023年05月25日 10:41:55 作者:极端~
这篇文章主要介绍了vue如何实现用户动态权限登录,文中的代码示例介绍的非常详细,对大家学习vue有一定的帮助,需要的朋友可以参考阅读
一、使用vue+elementUI搭登录框架,主要就是1、2、3、4
配置:
①vue.config.js
'use strict' const path = require('path') function resolve(dir) { return path.join(__dirname, dir) } // All configuration item explanations can be find in https://cli.vuejs.org/config/ module.exports = { publicPath: '/', outputDir: 'dist', assetsDir: 'static', lintOnSave: false, // 是否校验语法 productionSourceMap: false, devServer: { port: 8888, open: true, }, configureWebpack: { resolve: { alias: { '@': resolve('src') } } } }
②main.js
import Vue from "vue" import App from "./App.vue" import router from "./router" import store from "./store" import ElementUI from "element-ui" import 'element-ui/lib/theme-chalk/index.css' import "./router/router-config" // 路由守卫,做动态路由的地方 Vue.config.productionTip = false Vue.use(ElementUI) new Vue({ router, store, render: (h) => h(App), }).$mount("#app")
二、代码部分
- layout目录:
- layout/index.vue
<template> <el-container> <el-header> <header-temp></header-temp> </el-header> <el-container> <el-aside width="200px"><sidebar class="sidebar-container"></sidebar></el-aside> <el-main><app-main></app-main></el-main> </el-container> </el-container> </template> <script> import AppMain from './appMain' // 页面布局的右侧区域 import sidebar from './sideBar' // 页面布局的左侧菜单 import headerTemp from "./headerTemp" // 页面布局的header菜单 export default { name: 'layout', components: { sidebar, AppMain, headerTemp } } </script> <style> .el-header{padding: 0!important;margin-left: 180px;} </style>
①appMain/index.vue
<template> <section class="app-main"> <transition name="fade" mode="out-in"> <router-view></router-view> </transition> </section> </template> <script> export default { name: 'AppMain' } </script>
②headerTemp/index.vue
<template> <div class="header-temp-container"> <div class="userInfo"> <el-image :src="userInfo.avatar" class="eImage"></el-image> <el-dropdown @command="handleLogout"> <div class="detail user-link"> <span>{{ userInfo.name }}</span> <span>{{ userInfo.desc }}</span> <i class="el-icon--right"></i> </div> <template #dropdown> <el-dropdown-menu> <el-dropdown-item command="logout">退出</el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </div> </div> </template> <script> import { Message } from "element-ui" export default { name: "header-temp-container", data() { return { userInfo: JSON.parse(window.localStorage.getItem("userInfo")) } }, methods: { // 退出登录 handleLogout(key) { if(key == "logout") { window.localStorage.removeItem("userInfo") Message({ type: 'success', message: "退出登录", showClose: true, duration: 3000 }) this.$router.replace({ path: "/login" }) location.reload() } } } } </script> <style scoped> .header-temp-container{border-bottom: 1px solid #ddd; width: 100%;height: 60px;} .userInfo{display: flex;flex-direction: row;align-items: center;justify-content: flex-end;height: 100%;margin-right: 20px;} .eImage{width: 40px;height: 40px;border-radius: 50%;margin-right: 10px;} .detail{display: flex;flex-direction: column;align-items: flex-start;justify-content: space-around;} </style>
③sideBar/index.vue
<template> <el-menu mode="vertical" unique-opened :default-active="$route.path" background-color="#304156" text-color="#fff" active-text-color="#409EFF" > <sidebar-item :routes="routes"></sidebar-item> </el-menu> </template> <script> import sidebarItem from "./sidebarItem"; export default { components: { sidebarItem }, computed: { routes() { return this.$router.options.routes; }, }, }; </script> <style scoped> .sidebar-container { transition: width 0.28s; width: 180px !important; height: 100%; position: fixed; top: 0; bottom: 0; left: 0; z-index: 1001; } .sidebar-container a { display: inline-block; width: 100%; } .sidebar-container .svg-icon { margin-right: 16px; } .sidebar-container .el-menu { border: none; width: 100%; } </style> <style> a{text-decoration: none;} </style>
④sideBar/sidebarItem.vue
<template> <div class="menu-wrapper"> <template v-for="item in routes" v-if="!item.hidden && item.children"> <router-link v-if=" item.children.length === 1 && !item.children[0].children && !item.alwaysShow " :to="item.children[0].path" :key="item.children[0].name" > <el-menu-item :index="item.children[0].path" :class="{ 'submenu-title-noDropdown': !isNest }" > <span v-if="item.children[0].meta && item.children[0].meta.title">{{ item.children[0].meta.title }}</span> </el-menu-item> </router-link> <el-submenu v-else :index="item.name || item.path" :key="item.name"> <template slot="title"> <span v-if="item.meta && item.meta.title">{{ item.meta.title }}</span> </template> <template v-for="child in item.children" v-if="!child.hidden"> <sidebar-item :is-nest="true" class="nest-menu" v-if="child.children && child.children.length > 0" :routes="[child]" :key="child.path" > </sidebar-item> <router-link v-else :to="child.path" :key="child.name"> <el-menu-item :index="child.path"> <span v-if="child.meta && child.meta.title">{{ child.meta.title }}</span> </el-menu-item> </router-link> </template> </el-submenu> </template> </div> </template> <script> export default { name: "sidebarItem", props: { routes: { type: Array }, isNest: { type: Boolean, default: false, }, }, }; </script> <style scoped> .nest-menu .el-submenu > .el-submenu__title, .el-submenu .el-menu-item { min-width: 180px !important; background-color: #1f2d3d !important; } .nest-menu .el-submenu > .el-submenu__title, .el-submenu .el-menu-item :hover { background-color: #001528 !important; } .el-menu--collapse .el-menu .el-submenu { min-width: 180px !important; } </style>
- 路由配置
①router/index.js
import Vue from "vue" import VueRouter from "vue-router" const originalPush = VueRouter.prototype.push VueRouter.prototype.push = function push(location, onResolve, onReject) { if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject) return originalPush.call(this, location).catch(err => err) } Vue.use(VueRouter) const routes = [ { name: "login", path: "/login", meta: { title: "login" }, component: () => import("../views/login/index"), hidden: true } ] const router = new VueRouter({ routes }) export default router
- ②router/router-config.js
import router from "./index" import Layout from "../layout/index" import NProgress from 'nprogress' // progress bar NProgress.configure({ showSpinner: false }) // NProgress Configuration const filterRoutes = ["/login"] // 需要过滤掉的路由 router.beforeEach((to, from, next) => { // start progress bar NProgress.start() // 获取路由 meta 中的title,并设置给页面标题 document.title = "动态路由(" + to.meta.title + ")" // 判断路由指向是否在需要过滤的路由地址数组里 // 如果在,则直接跳进页面,无需判断 if(filterRoutes.indexOf(to.path) !== -1) { next() return false } if(router.options.routes.length == 1) { // 获取token和原始路由数组 const userInfo = JSON.parse(window.localStorage.getItem('userInfo')) ?? "" // 当token和原始路由都存在的时候 if(userInfo.token && userInfo.routes) { onFilterRoutes(to, next, userInfo.routes) // 执行路由过滤和跳转 } else { next({ path: "/login", replace: true }) } } else next() }) router.afterEach(() => { // finish progress bar NProgress.done() }) // 路由拼接 function loadView(view) { return () => import(`@/views/${ view }`) } // 路由过滤和跳转 async function onFilterRoutes(to, next, e) { const routes = await filterASyncRoutes(e) // 路由过滤 routes.sort((a, b) => a['id'] - b['id']) routes.forEach(item => { router.options.routes.push(item) router.addRoute(item) }) next({ ...to, replace: true }) } // 路由过滤 遍历路由 转换为组件对象和路径 function filterASyncRoutes(data) { const routes = data.filter(item => { if(item["component"] === "Layout") item.component = Layout else item["component"] = loadView(item["component"]) // 路由递归,转换组件对象和路径 if(item["children"] && item["children"].length > 0) item["children"] = filterASyncRoutes(item.children) return true }) return routes }
- 登录(views/login/index.vue)
<template> <div class="login-wrapper"> <div class="modal"> <el-form :model="user" status-icon :rules="rules" ref="userForm"> <div class="title">动态路由</div> <el-form-item prop="username"> <el-input type="text" prefix-icon="el-icon-user" placeholder="请输入用户名" v-model="user.username" /> </el-form-item> <el-form-item prop="password"> <el-input type="password" prefix-icon="el-icon-view" placeholder="请输入密码" v-model="user.password" /> </el-form-item> <el-form-item> <el-button type="primary" class="btn-login" @click="login">登录</el-button> </el-form-item> <div class="toast"> <span>管理员账号:admin </span> <span>密码:654321</span> </div> <div class="toast"> <span>普通人员账号:people</span> <span>密码:123456</span> </div> </el-form> </div> </div> </template> <script> import dynamicUser from "../../mock" import { Message } from "element-ui" export default { name: 'login', data() { return { user: { username: "", password: "" }, rules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ] } } }, methods: { login() { this.$refs.userForm.validate(( valid ) => { if(valid) { let flag = !1 window.localStorage.removeItem("userInfo") dynamicUser.forEach(item => { if(item["username"] == this.user['username'] && item["password"] == this.user['password']) { flag = !0 Message({ type: 'success', message: "登录成功", showClose: true, duration: 3000 }) window.localStorage.setItem("userInfo", JSON.stringify(item)) this.$router.replace({ path: "/" }) } }) if(!flag) Message({ type: 'warning', message: "账号密码错误,请重试!", showClose: true, duration: 3000 }) } else return false }) } } } </script> <style scoped> .login-wrapper { display: flex; flex-direction: row; align-items: center; justify-content: center; background-color: #fff; width: 100vw; height: 100vh; } .modal { width: 360px; height: 380px; box-shadow: 0 0 10px 5px #ddd; padding: 50px; border-radius: 5px; } .title { width: 100%; text-align: center; line-height: 1.5; font-size: 50px; margin-bottom: 30px; } .btn-login { width: 100%; } .toast{ width: 100%; display: flex; flex-direction: row; align-items: center; justify-content: space-between; height: 50px; } </style>
- 动态返回路由
使用mock.js造了一条路由,后端返回格式类似于下列这种样式:
const dynamicUser = [ { name: "管理员", avatar: "https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/ccb565eca95535ab2caac9f6129b8b7a~300x300.image", desc: "管理员 - admin", username: "admin", password: "654321", token: "rtVrM4PhiFK8PNopqWuSjsc1n02oKc3f", routes: [ { id: 1, name: "/", path: "/", component: "Layout", redirect: "/index", hidden: false, children: [ { name: "index", path: "/index", meta: { title: "index" }, component: "index/index" }, ]}, { id: 2, name: "/form", path: "/form", component: "Layout", redirect: "/form/index", hidden: false, children: [ { name: "/form/index", path: "/form/index", meta: { title: "form" }, component: "form/index" } ]}, { id: 3, name: "/example", path: "/example", component: "Layout", redirect: "/example/tree", meta: { title: "example" }, hidden: false, children: [ { name: "/tree", path: "/example/tree", meta: { title: "tree" }, component: "tree/index" }, { name: "/copy", path: "/example/copy", meta: { title: "copy" }, component: "tree/copy" } ] }, { id: 4, name: "/table", path: "/table", component: "Layout", redirect: "/table/index", hidden: false, children: [ { name: "/table/index", path: "/table/index", meta: { title: "table" }, component: "table/index" } ] }, { id: 5, name: "/admin", path: "/admin", component: "Layout", redirect: "/admin/index", hidden: false, children: [ { name: "/admin/index", path: "/admin/index", meta: { title: "admin" }, component: "admin/index" } ] }, { id: 6, name: "/people", path: "/people", component: "Layout", redirect: "/people/index", hidden: false, children: [ { name: "/people/index", path: "/people/index", meta: { title: "people" }, component: "people/index" } ] } ] }, { name: "普通用户", avatar: "https://img0.baidu.com/it/u=2097980764,1024880469&fm=253&fmt=auto&app=138&f=JPEG?w=300&h=300", desc: "普通用户 - people", username: "people", password: "123456", token: "4es8eyDwznXrCX3b3439EmTFnIkrBYWh", routes: [ { id: 1, name: "/", path: "/", component: "Layout", redirect: "/index", hidden: false, children: [ { name: "index", path: "/index", meta: { title: "index" }, component: "index/index" }, ]}, { id: 2, name: "/form", path: "/form", component: "Layout", redirect: "/form/index", hidden: false, children: [ { name: "/form/index", path: "/form/index", meta: { title: "form" }, component: "form/index" } ]}, { id: 6, name: "/people", path: "/people", component: "Layout", redirect: "/people/index", hidden: false, children: [ { name: "/people/index", path: "/people/index", meta: { title: "people" }, component: "people/index" } ] } ] } ] export default dynamicUser
以上就是vue实现用户动态权限登录的代码示例的详细内容,更多关于vue 用户动态权限登录的资料请关注脚本之家其它相关文章!
您可能感兴趣的文章:
最新评论