Vue + Element-UI —— 项目实战(八)(完结)

简介: Vue + Element-UI —— 项目实战(八)(完结)

项目演示

项目教学视频链接

https://www.bilibili.com/video/BV1dY411T71E?t=37.4

vue + element-ui 项目演示

八、项目实战八

Ⅰ、登录界面

1. 编写 login 页面
  1. ./views/Login/login.vue,编写登录页面
  <template>
    <!--status-icon: 在输入框中显示校验结果反馈图标 -->
    <el-form
      :model="form"
      status-icon
      :rules="rules"
      ref="form"
      label-width="100px"
      class="login-container"
    >
      <h3 class="login_title">系统登录</h3>
      <!-- prop:定义在form中对应的字段 -->
      <el-form-item
          label="用户名"
          label-width="80px"
          prop="username"
          class="username"
      >
          <!-- autocomplete:表单是否启用自动完成功能。自动完成允许浏览器对字段的输入,是基于之前输入过的值。 -->
          <el-input
              type="input"
              v-model="form.username"
              autocomplete="off"
              placeholder="请输入账号"
          >
          </el-input>
      </el-form-item>
      <el-form-item
          label="密码"
          label-width="80px"
          prop="password"
      >
          <el-input
              type="password"
              v-model="form.password"
              autocomplete="off"
              placeholder="请输入密码"
          ></el-input>
      </el-form-item>
      <el-form-item class="login_submit">
          <el-button type="primary" @click="login" class="login_submit">登录</el-button>
      </el-form-item>
    </el-form>
  </template>
  <script>
  // import Mock from 'mockjs'
  import {getMenu} from '../../api/data'
  export default {
    name: "Login",
    data() {
      return {
        form: {},
        // 表单校验的定义
        rules: {
          username: [
            // 用户名校验:必需、没有输入会有提示、失去焦点触发
            { required: true, message: "请输入用户名", trigger: "blur" },
            {
              min: 3,
              message: "用户名长度不能小于3位",
              trigger: "blur",
            },
          ],
          // 密码校验:必需、提示、失去焦点触发
          password: [{ required: true, message: "请输入密码", trigger: "blur" }],
        },
      };
    },
  };
  </script>
  <style lang="less" scoped>
  .login-container {
      border-radius: 15px;
      // 背景裁剪的内边距
      background-clip: padding-box;
      margin: 180px auto;
      width: 350px;
      padding: 35px 35px 15px 35px;
      background-color: #fff;
      border: 1px solid #eaeaea;
      box-shadow: 0 0 25px #cac6c6;
  }
  .login_title {
      margin: 0px auto 40px auto;
      text-align: center;
      color: #505458;
  }
  .login_submit {
      margin: 10px auto 0 auto;
  }
  </style>

登录页面

0f6fa65646544f6e88820df3897bdf88.png

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
      }
    }

登录成功

fd2e3748c81a4e45bf5c8e8be9bba61e.png

43584b07253a4402a40de83739c2de98.png

Ⅱ、权限管理问题 & 退出登录

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"); //跳转到登录界面
    }

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

b33cb2470e6c41bd9e94d162e17f38ea.png

不积跬步无以至千里,不积小流无以成江海

相关文章
|
2天前
|
JavaScript 前端开发
如何优雅的只在当前页面中覆盖ui库中组件的样式(vue的问题)
如何优雅的只在当前页面中覆盖ui库中组件的样式(vue的问题)
20 0
如何优雅的只在当前页面中覆盖ui库中组件的样式(vue的问题)
|
2天前
|
JavaScript 前端开发
vue element-ui分页插件 始终保持在页面底部样式
vue element-ui分页插件 始终保持在页面底部样式
36 0
|
2天前
|
JavaScript
Vue给Element UI的el-popconfirm绑定按钮事件
Vue给Element UI的el-popconfirm绑定按钮事件
|
2天前
|
JavaScript
vue element-ui中有关表格中的数据整条显示红色/绿色等等颜色的问题
vue element-ui中有关表格中的数据整条显示红色/绿色等等颜色的问题
31 1
|
2天前
|
JavaScript
vue中有关表格中的表格头中添加悬浮提示的ui问题
vue中有关表格中的表格头中添加悬浮提示的ui问题
20 1
|
2天前
|
资源调度 JavaScript
Vue + Element-ui组件上传图片报错问题解决方案
Vue + Element-ui组件上传图片报错问题解决方案
|
2天前
|
存储 JavaScript 前端开发
从入门到项目实战 - Vue 列表渲染
从入门到项目实战 - Vue 列表渲染
57 0
|
2天前
|
JavaScript
VUE里修改element-ui的显示层次与上下间隔
VUE里修改element-ui的显示层次与上下间隔
13 1
|
2天前
|
JavaScript 前端开发 开发者
前端框架(Vue.js&&vue-cli项目框架&&element-ui使用)
前端框架(Vue.js&&vue-cli项目框架&&element-ui使用)
|
2天前
|
JavaScript
vue element ui 打开弹窗出现黑框问题
vue element ui 打开弹窗出现黑框问题
21 1