Vue + Element-UI —— 项目实战(八)(完结,2024年最新抖音四面被拒再战头条终获offer

41 阅读3分钟
2. 登录权限 & 导航守卫
  1. 安装缓存插件

	npm i js-cookie

  1. 在 store 文件中,创建 user.js 文件,用于缓存输入的内容。

	import Cookie from "js-cookie";
	
	export default {
	  state: {
	    token: "",
	  },
	  mutations: {
	    // 设置cookie
	    setToken(state, val) {
	      (state.token = val), Cookie.set("token", val); //cookie的名称,传入的值
	    },
	    // 清除cookie
	    clearToken(state) {
	      (state.token = ""), Cookie.remove("token");
	    },
	    // 获取cookie
	    getToken(state) {
	      // 如果当前的缓存中有token,直接获取。如果没有,要从state中获取
	      state.token = Cookie.get("token") || state.token;
	    },
	  },
	};

  1. 在 ./store/index.js 中导入

	import Vue from 'vue'
	import Vuex from 'vuex'
	import tab from './tab'
	import user from './user'
	// 全局使用Vuex
	Vue.use(Vuex)
	export default new Vuex.Store({
	    // 模块化定义
	    modules:{
	        tab,
	        user
	    }
	})

  1. main.js 中添加前置路由守卫

	// 前置路由守卫
	router.beforeEach((to, from, next) => {
	  store.commit('getToken') //防止页面刷新后vuex丢失token信息
	  const token = store.state.user.token
	  // 如果token不存在,并且当前页不是登录页
	  if(!token && to.name !== 'login') {
	    next({name: 'login'}) // 返回登录页
	  } else if(token && to.name === 'login'){
	    next({name: 'home'})
	  } else {
	    next()
	  }
	})

2. 登录接口逻辑
  1. ./api/mockServerData/permission.js,用于定义接口相关的逻辑

	// 接口的相关逻辑
	import Mock from 'mockjs'
	export default {
	  // 模拟菜单权限,接收传递进来的参数
	  getMenu: config => {
	    console.log(config);
	    const { username, password } = JSON.parse(config.body)
	    console.log(JSON.parse(config.body))
	    // 先判断用户是否存在
	    // 判断账号和密码是否对应
	    if (username === 'admin' && password === 'admin') {
	      return {
	        code: 20000,
	        data: {
	          menu: [
	            {
	              path: '/home',
	              name: 'home',
	              label: '首页',
	              icon: 's-home',
	              url: 'home/index'
	            },
	            {
	              path: '/mall',
	              name: 'mall',
	              label: '商品管理',
	              icon: 'video-play',
	              url: 'mall/index'
	            },
	            {
	              path: '/user',
	              name: 'user',
	              label: '用户管理',
	              icon: 'user',
	              url: 'User/index'
	            },
	            {
	              label: '其他',
	              icon: 'location',
	              children: [
	                {
	                  path: '/page1',
	                  name: 'page1',
	                  label: '页面1',
	                  icon: 'setting',
	                  url: 'other/pageOne.vue'
	                },
	                {
	                  path: '/page2',
	                  name: 'page2',
	                  label: '页面2',
	                  icon: 'setting',
	                  url: 'other/pageTwo.vue'
	                }
	              ]
	            }
	          ],
	          token: Mock.Random.guid(),
	          message: '获取成功'
	        }
	      }
	    } else if (username === 'xiaoxiao' && password === 'xiaoxiao') {
	      return {
	        code: 20000,
	        data: {
	          menu: [
	            {
	              path: '/',
	              name: 'home',
	              label: '首页',
	              icon: 's-home',
	              url: 'home/index'
	            },
	            {
	              path: '/mall',
	              name: 'mall',
	              label: '商品管理',
	              icon: 'video-play',
	              url: 'mall/index'
	            }
	          ],
	          token: Mock.Random.guid(),
	          message: '获取成功'
	        }
	      }
	    } else {
	      return {
	        code: -999,
	        data: {
	          message: '密码错误'
	        }
	      }
	    }
	  }
	}

  1. 在 mock.js 中进行接口拦截

	import permissionApi from './mockServerData/permission'
	Mock.mock(/permission\/getMenu/, 'post', permissionApi.getMenu)

3. 菜单权限功能
  1. 动态添加路由,在 tab.js 中定义 menu 空数组

	menu: []

  1. 在 tab.js 的 mutations 中添加修改方法

	setMenu(state, val) {
      state.menu = val
      Cookie.set('menu', JSON.stringify(val))
    },
    clearMenu(state) {
      state.menu = []
      Cookie.remove('menu')
    },
    addMenu(state, router) {
      if(!Cookie.get('menu')) {
        return 
      }
      // 转成对象
      const menu = JSON.parse(Cookie.get('menu'))
      state.menu = menu
      const menuArray = []
      menu.forEach(item => {
        // 有二级菜单的数据
        if(item.children) {
          item.children = item.children.map(item => {
            item.component = () => import(`../views/${item.url}`)
            return item
          })
          menuArray.push(...item.children)
          // 一级菜单
        }else{
          item.component = () => import(`../views/${item.url}`)
          menuArray.push(item)
        }
      })
      // 路由的动态添加
      menuArray.forEach(item => {
        router.addRoute('Main', item)
      })
    }

  1. login.vue 中添加方法

	login() {
      getMenu(this.form).then((res) => {
        console.log(res, "res");
        // 接口调用成功
        if (res.code === 20000) {
          // 登录成功后,清除当前路由
          this.$store.commit("clearMenu");
          // 设置路由,传入数据
          this.$store.commit("setMenu", res.data.menu);
          // 设置token,传入接口的数据
          this.$store.commit("setToken", res.data.token);
          // 动态添加路由,传入router 实例
          this.$store.commit("addMenu", this.$router); 
          // 页面跳转
          this.$router.push({ name: "home" });
        } else {
          //失败的提示
          this.$message.warning(res.data.message);
        }
      });
    }

这样就可以把 CommonAside.vue 中写死的数据去掉,只留 menu: []。
.router/index.js 中里面的数据都删掉,只保留 children: []。

  1. 在 CommonAside.vue 中定义 asyncMenu(),用来获取 menu

	computed: {
	    noChildren() {
	      // 过滤出来没有子项目的数据
	      return this.asyncMenu.filter((item) => !item.children);
	    },
	    hasChildren() {
	      // 过滤出有子项目的数据
	      return this.asyncMenu.filter((item) => item.children);
	    },
	    isCollapse() {
	      return this.$store.state.tab.isCollapse;
	    },
	    asyncMenu() {
	      // 获取menu
	      return this.$store.state.tab.menu
	    }
	  }

登录成功

在这里插入图片描述
在这里插入图片描述

Ⅱ、权限管理问题 & 退出登录
1. 刷新白屏的解决方法
  1. main.js 中,在 vue实例生成前, created 钩子中调用动态路由的方法。

	created() {
      store.commit('addMenu', router)
    }

2. 权限管理

已经登录后,不应该还能访问登录页面,而是让它跳转到首页。

  1. 在 main.js 中修改路由守卫

	router.beforeEach((to, from, next) => {
	  store.commit('getToken') //防止页面刷新后vuex丢失token信息
	  const token = store.state.user.token
	  // 如果token不存在,并且当前页不是登录页
	  if(!token && to.name !== 'login') {
	    next({name: 'login'}) // 返回登录页
	  } else if(token && to.name === 'login'){
	    next({name: 'home'})
	  } else {
	    next()
	  }
	})

3. 退出功能

在 CommonHeader.vue 中添加退出功能

	<el-dropdown-menu slot="dropdown">
      <el-dropdown-item>个人中心</el-dropdown-item>
      <el-dropdown-item @click.native="logOut">退出</el-dropdown-item>
    </el-dropdown-menu>

	logOut() {
      this.$store.commit("clearToken"); //清除token
      this.$store.commit("clearMenu"); //清除menu
      this.$router.push("/login"); //跳转到登录界面
    }

点击退出,返回到登录界面

在这里插入图片描述

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。 img img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!