Vue+Element Ui 登陆页面 笔记

记录一下上课学到的东西,主要内容来自projects/M03_基于RBAC的通用后台管理系统设计 · 北京大学-张齐勋/敏捷软件开发 - 码云 - 开源中国 (gitee.com)

但是因为老师的代码没有每个都注释,所以加上了一些小白的备注和自己的代码。

1.创建Vue项目


? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◉ Router
 ◉ Vuex
❯◉ CSS Pre-processors
 ◯ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

2.目录结构

后台管理系统项目中,包含了如下几个目录:

  • components:包含了项目中所有的公共组件,例如表格、树形菜单、图表等组件。
  • api: 包含了项目中所有的后端接口相关的文件,包括接口的封装和请求方式的定义等。
  • router:包含了项目中的前端路由配置文件,用于定义前端路由规则。
  • store:包含了项目中的 Vuex 状态管理模块,用于管理应用程序的状态和数据流。
  • views:包含了项目中所有的业务组件,例如系统管理、任务调度等组件,每个组件对应一个页面。
  • utils:包含了项目中的工具类文件,例如日期处理、字符串处理、请求(axios)封装等工具类文件。
  • layout:用于存放系统的基本布局模板。该目录下的文件通常包括顶部导航栏、左侧菜
  • 单栏、底部版权信息等。

3.用户登录

a.安装依赖包

npm i element-ui -S
npm i axios -S

b.集成element UI

在main.js中加入

import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';

Vue.use(ElementUI);

new Vue({
  el: '#app',
  render: h => h(App)
});

注解:

/ 通常情况下,我们会在main.js中引入一些全局的配置,例如路由、状态管理器、第三方库等等,然后在Vue实例中注入它们。而在组件中,我们通常只引入和使用组件相关的依赖。

// 但是,在实际开发中,并没有什么固定的规则。有时候,我们可能需要在组件中引入一些全局的依赖,例如Element UI、Axios等等。在这种情况下,我们需要在组件中单独引入它们。

// 总的来说,如果一个依赖是在整个应用中都要使用的,就应该在main.js中引入;如果一个依赖只在某个组件中使用,就应该在组件中引入。

// 在这个文件中,需要引入以下值:

// App.vue:这是应用程序的根组件,包含应用程序的主要布局和逻辑。

// router:这是 Vue Router 的实例,包含应用程序的所有路由信息和导航守卫。

// store:这是 Vuex 的实例,包含应用程序的状态管理逻辑。

// ElementUI:这是 UI 框架 ElementUI 的实例,用于渲染应用程序的 UI 组件和样式。

// 除此之外,如果你的应用程序需要其他的库或模块,也可以在这里引入它们。

c.设计登陆页面

在views/LoginView.vue中

 代码略(详见Gitee)

d.设置路由

在router/inde.js中

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
import Layout from '@/layout/IndexPage.vue'
Vue.use(VueRouter)
{
    path: '/login',
    name: 'login',
    component: () => import('../views/Login.vue')
},

// path:路由匹配的路径,可以是字符串、正则表达式或者一个包含路径的数组。

// name:路由的名称,方便在程序中进行路由跳转。

// component:对应的组件,可以是通过 import 引入的组件,也可以是一个懒加载的组件。

// children:子路由,是一个数组,可以嵌套多层。

// redirect:重定向,当用户访问某个路径时,可以自动跳转到另外一个路径。

// meta:元信息,可以在路由配置中添加一些自定义的数据,比如页面标题、页面描述等。

// props:传递给组件的 props 数据,可以是一个对象或者是一个布尔值。

f.封装axios请求

在utils/request.js中

// 这个文件导出了一个名为service的Axios实例,主要用于封装与后端API的交互。
// 在这个文件中,使用了axios.create方法创建了一个axios实例,其中指定了基础URL和超时时间。
// 接着,使用了service.interceptors.request.use和service.interceptors.response.use来拦截请求和响应,并在请求或响应前对数据进行处理。
// 通过这种方式,在其他文件中引入这个service实例,可以直接调用Axios提供的各种HTTP请求方法,
// 同时也可以通过在拦截器中进行一些统一的处理,比如添加token、请求头等。这样可以提高代码的复用性和可维护性。


//对axios进行封装
import axios from 'axios';


const service = axios.create({
  baseURL: 'https://mock.apifox.cn/m1/2428381-0-default/admin-api',
  timeout: 5000
});

// 使用service.interceptors.request.use()方法添加了请求拦截器,在请求发送之前可以对请求的配置进行一些处理,
// 如设置请求头、请求参数等,可以在config参数中进行配置。处理完后必须返回config对象或者一个promise对象,用于后续的处理。
// 如果请求出错,则可以在error参数中进行处理。

service.interceptors.request.use(
  config => {
    // 在请求发送之前对请求数据进行处理
    // ...
    
    return config;
  },
  
  error => {
    // 对请求错误做些什么
    console.log(error);
    return Promise.reject(error);
  }
);

// 上述代码使用service.interceptors.response.use()方法添加了响应拦截器,在获取响应数据之前可以对响应数据进行一些处理,如解析数据、判断状态码等,可以在response参数中进行处理。
// 处理完后必须返回response对象或者一个promise对象,用于后续的处理。
// 如果响应出错,则可以在error参数中进行处理
service.interceptors.response.use(
  response => {
    // 对响应数据进行处理
    // ...

    return response.data;
  },
  error => {
    // 对响应错误做些什么
    console.log(error);
    return Promise.reject(error);
  }
);

// 最后,通过export default导出该axios实例,
// 以便在其他模块中引用该实例进行请求。
export default service;

g.封装api请求

在api/login.js中

import request from '@/utils/request'

// 用户登录
export function login(username, password) {
  const data = {
    username,
    password
  }
  return request({
    url: '/user/login',
    method: 'post',
    data: data
  })
}


// 获取用户信息
export function getInfo() {
  return request({
    url: '/user/getInfo',
    method: 'get'
  })
}

// import request from 'request.js' 这行代码实际上是从一个名为 request.js 的文件中导入默认导出的模块,并将其赋值给 request 变量。

// 具体来说,它会:

// 根据相对路径 'request.js' 找到对应的文件。

// 加载该文件,并执行其中的代码。

// 找到文件中的默认导出,该导出可以是任意类型的值(对象、函数、字符串等),但必须是唯一的。

// 将该导出赋值给 request 变量,以便在当前文件中使用它。

h.处理登陆操作

import {login} from '@/api/login.js'

            login(this.username,this.password).then(res =>{
              this.$router.push({ path: '/' })
            }).catch(() => {
              // 登录失败,显示错误提示
              this.$message.error('用户名或密码错误')
              this.loading = false
            })

        // <el-form ref="form" :model="loginForm" :rules="rules" label-position="left" label-width="0">

        // 使用id的情况:const form = document.getElementById('login-form')

        // validate 是 element-ui 表单组件提供的一个方法,用于表单验证。

        // 可以通过 this.$refs.form.validate() 方法来调用,其中 form 是表单组件的 ref 属性值。

        // validate 方法会执行表单验证规则,如果表单验证通过则返回 true,否则返回 false。

i.登陆成功页面

代码略

j.菜单增加路由跳转

@click="$router.push('/rbac/user/list')"

4.路由与菜单

a.layout布局

layout/index.vue

代码略

路由嵌套:

import Layout from '@/layout/IndexPage.vue'

// 如果 @/layout 目录下只有一个 index.vue 文件,那么这个 Layout 组件很有可能就是该文件导出的默认 Vue 组件。在这种情况下,import Layout from '@/layout' 就相当于从 @/layout 目录中导入默认的 Vue 组件,并将其赋值给名为 Layout 的变量。在代码中,这个 Layout 组件可以通过变量 Layout 访问和使用。

// 如果 layout 目录下有多个文件,通常情况下会存在一个默认导出的文件,如 index.vue,它通常被用作布局组件的容器。同时也可以定义其他子组件,这些组件可以是单独的 .vue 文件,也可以是 .js 或 .ts 文件,然后再由布局组件去引用它们。最终,这些组件会被组合起来构成一个完整的布局。布局组件的具体结构和设计根据项目需求和开发者的喜好而定。

{
    path: '/',

    component: Layout,
    children:[{
      path:"/",
      name: 'home',
      component:HomeView
    }]
  },

b.设计子页面:代码略

5.权限控制

        a.处理Token

在utils/auth.js中

// 这段代码是与应用程序中使用的令牌有关的代码,具体来说是使用了 localStorage 来存储和检索访问令牌。其中 ACCESS_TOKEN 是一个常量,用于定义存储在 localStorage 中的键名,即用于保存访问令牌的键名。

// getAccessToken():从 localStorage 中获取访问令牌。

// setToken(token):将访问令牌存储到 localStorage 中。

// removeToken():从 localStorage 中删除访问令牌。


const AccessTokenKey = 'ACCESS_TOKEN'

// ========== Token 相关 ==========

export function getAccessToken() {
  return localStorage.getItem(AccessTokenKey)
}

// localStorage 是 HTML5 提供的一种本地存储方式,可以用来存储简单的键值对。它可以在浏览器关闭后仍然保留存储的数据,因此非常适合存储用户的持久化数据,如用户的偏好设置、登录信息等。

// localStorage 只能存储字符串类型的数据,因此如果要存储其他类型的数据,需要将它们转换成字符串类型再进行存储。可以使用 JSON.stringify() 将 JavaScript 对象转换为 JSON 格式的字符串,使用 JSON.parse() 将 JSON 格式的字符串转换为 JavaScript 对象。

export function setToken(token) {
  localStorage.setItem(AccessTokenKey, token)
}

export function removeToken() {
  localStorage.removeItem(AccessTokenKey)
}

b.成功后保存token

在view/LoginView.vue中

  import {setToken} from '@/utils/auth'

  setToken(res.data.token)

c.权限检查

在src中建立permission.js

import router from './router'

import { getAccessToken } from '@/utils/auth'

router.beforeEach((to, from, next) => {
  if (getAccessToken()) {
    if (to.path === '/login') {
      next({ path: '/' })
    } 
    next()
  } else {
    // 没有token
    if (to.path === '/login') {
      // 直接进入
      next()
    } else {
      next('/login') // 否则全部重定向到登录页
    }
  }
})

router.afterEach(() => {
  
})

在main.js中引入使用

import './permission' 

这样如果有token的话直接进入,不用重复登陆,否则转入登陆页面,必须先登录才能进入管理页面。

d.退出功能

增加退出菜单,代码略

清除token(在Layout页面)

<script>
import {removeToken} from '@/utils/auth'
export default {
  name: "MyComponent",
  methods: {
    logout() {
      this.$confirm('确定注销并退出系统吗?', '提示').then(() => {
        removeToken()
        this.$router.push({ path: '/login' })
      }).catch(() => {});
    },
  },
};
</script>

每次请求时携带token(在LoginView.vue文件)

import {getAccessToken} from '@/utils/auth'



// 在请求发送之前对请求数据进行处理
    // ...
    if (getAccessToken() ) {
      config.headers['Authorization'] = 'Bearer ' + getAccessToken() // 让每个请求携带自定义token 请根据实际情况自行修改
    }

加上一些整活之后自己做出来是这样:

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值