登录页面设计

该节记录了登录界面的设计,以及 vuex 的简单实用,然后将首页简单搭建完成。

先看最终效果图

先在 views 文件夹下 新建 login/index.vue 文件。用于登录首页

vuex 对应 用户模块

vuex 相关介绍可参考另一篇博文,链接

新建 store/modules/user.js,将登录状态及内容保存到状态管理器中,内容如下:

import router from '@/router'

export default {
state: {
userInfo: null, //用户信息
token: null,
},
getters: {
userInfo: (state) => {
if (state.userInfo == null) {
let sessionUser = sessionStorage.getItem('user')
if (sessionUser != null) {
state.userInfo = JSON.parse(sessionUser)
return sessionUser
} else {
let localeUser = localStorage.getItem('user')
if (localeUser != null) {
state.userInfo = JSON.parse(localeUser)
}
return localeUser
}
}
return state.userInfo
},
token: (state) => {
if (state.token == null) {
let sessionToken = sessionStorage.getItem('token')
if (sessionToken != null) {
state.token = sessionToken
return sessionToken
} else {
let localeToken = localStorage.getItem('token')
state.token = localeToken
return localeToken
}
}
return state.token
},
},
mutations: {
setToken(state, token, flag = true) {
if (flag) {
localStorage.setItem('token', token)
} else {
sessionStorage.setItem('token', token)
}
},
setUserInfo(state, userInfo, flag = true) {
state.userInfo = userInfo
state.token = userInfo.token
if (flag) {
localStorage.setItem('user', JSON.stringify(userInfo))
} else {
sessionStorage.setItem('user', JSON.stringify(userInfo))
}
this.commit('setToken', userInfo.token, flag)
},
logout(state) {
state.userInfo = null
state.token = null
localStorage.removeItem('token')
localStorage.removeItem('user')
sessionStorage.removeItem('token')
sessionStorage.removeItem('user')
router.push('/login')
},
},
actions: {},
}

然后再在 store/index.js 中将 user 模块引入进来,代码如下:

import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex) import user from './modules/user' const store = new Vuex.Store({
modules: {
user: user,
},
})
export default store

丰富界面

使用 element 的 from 组件,进行设计登录界面。界面代码如下:

<template>
<div class="loginContain">
<div class="loginBox">
<h2 class="loginH2"><strong>Vue</strong> 后台管理系统</h2>
<el-form :model="loginForm" :rules="loginFormRules" ref="loginForm" label-position="left" label-width="0px" class="login-form">
<el-form-item prop="username">
<el-input type="text" v-model="loginForm.username" auto-complete="off" placeholder="请输入账号">
<i slot="prefix" class="el-input__icon el-icon-user-solid"></i>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input type="password" v-model="loginForm.password" auto-complete="off" placeholder="密码">
<i slot="prefix" class="el-input__icon el-icon-lock"></i>
</el-input>
</el-form-item>
<el-form-item style="width:100%;">
<el-button type="primary" style=" width: 100%; background: #19b9e7;" @click.native.prevent="login" :loading="logining">登 录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>

登录相关 脚本 代码如下:

<script>
export default {
data() {
return {
logining: false,
loginForm: {
username: 'admin',
password: '123456',
},
notifyObj: null,
loginFormRules: {
username: [{ required: true, message: '请输入账号', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
},
}
},
//引入组件
components: {},
// 方法
methods: {
login() {
this.logining = true
let userInfo = { username: this.loginForm.username, password: this.loginForm.password }
this.$api.login(userInfo).then((res) => {
if (res.success) {
this.$store.commit('setUserInfo', res.data)
this.$message({
type: 'success',
message: '登录成功',
duration: 800,
}) let redirect = '/'
if (this.$route.query.redirect !== undefined) {
redirect = this.$route.query.redirect
}
setTimeout(() => {
this.logining = false
this.$router.push(redirect)
if (this.notifyObj) {
this.notifyObj.close()
}
this.notifyObj = null
}, 800)
} else {
this.logining = false
this.$message({
type: 'error',
message: '账号或密码错误',
})
}
})
},
},
// 计算属性
computed: {},
//未挂载DOM,不能访问ref为空数组
//可在这结束loading,还做一些初始化,实现函数自执行,
//可以对data数据进行操作,可进行一些请求,请求不易过多,避免白屏时间太长。
created() {},
//可在这发起后端请求,拿回数据,配合路由钩子做一些事情;可对DOM 进行操作
mounted() {
this.notifyObj = this.$notify({
title: '提示',
message: '管理员,账号分别为:admin,密码都为:123456',
duration: 4000,
iconClass: 'el-icon-s-opportunity',
})
},
}
</script>

对界面进行 简单的样式调整,设置背景等,代码如下:

<style lang="scss" scoped>
$inputHeight: 48px; .loginContain {
height: 100%;
width: 100%;
background: url(../../assets/img/loginbg.jpg) no-repeat center center;
background-size: 100% 100%;
overflow: hidden;
}
.loginBox {
height: 455px;
width: 550px;
margin: 0 auto;
position: relative;
top: 20%;
}
.loginH2 {
font-size: 28px;
color: #fff;
text-align: center;
} .el-input {
background-color: transparent;
border-radius: 20px;
height: $inputHeight;
color: #ffffff !important;
border: rgba(255, 255, 255, 0.2) 2px solid !important;
}
::v-deep .el-input__inner {
padding-left: 30px;
background-color: transparent !important;
border: none !important;
height: $inputHeight !important;
color: #ffffff !important;
}
.login-form {
-webkit-border-radius: 5px;
border-radius: 5px;
-moz-border-radius: 5px;
background-clip: padding-box;
margin: 10px auto;
width: 380px;
padding: 35px 35px 15px 35px;
}
</style>

相关接口上一篇文章中有写,这里就不再赘述了。

mock 接口截图如下,

既然涉及到登录,那肯定需要进行权限判断,所以我们使用 路由前置守卫进行控制,

const WhiteListRouter = ['/login', '/notfound'] // 路由白名单
//导航守卫 路由开始前
router.beforeEach((to, from, next) => {
let user = store.getters.userInfo
let token = store.getters.token
var hasAuth = user !== null && token !== null && user !== undefined && token !== undefined
if (to.path == '/login') {
if (hasAuth) {
next({ path: '/' })
} else {
next()
}
} else {
if (!hasAuth) {
//没登录的情况下 访问的是否是白名单
if (WhiteListRouter.indexOf(to.path) !== -1) {
next()
} else {
next({
path: '/login',
})
}
} else {
next()
}
}
})

路由相关代码

const routes = [
{
path: '/',
name: 'home',
component: () => import('@/views/home'),
children: [
{
path: '',
name: '首页',
component: () => import('@/views/home/defaultPage'),
},
],
},
{
path: '/login',
name: 'login',
component: login,
},
{
path: '/notfound',
name: 'notfound',
component: () => import('@/views/notfound'),
},
{
path: '*',
redirect: '/notfound',
name: 'notfound',
component: () => import('@/views/notfound'),
},
]

其中涉及到的相关页面,就只有自己建了。

首页相关代码

完整代码:

<!-- 首页 -->
<template>
<el-container>
<el-header class="header">
<!-- logo -->
<div class="logo" :class="isCollapse ? 'logo-collapse-width' : 'logo-width'">
<img v-if="isCollapse" src="@assets/logo6065.png" />
<img v-else src="@assets/logo.png" />
</div>
<!-- 折叠按钮 -->
<div class="tools" @click.prevent="collapse">
<i class="el-icon-menu"></i>
</div>
<!-- 头部导航栏 -->
<div class="heardNavBar">
<el-menu default-active="1" class="el-menu-demo" background-color="#4b5f6e" text-color="#fff" active-text-color="#ffd04b" mode="horizontal">
<el-menu-item index="1" @click="$router.push('/')">首页</el-menu-item>
<el-menu-item index="2" @click="openUrl('#')">使用文档</el-menu-item>
<el-menu-item index="3" @click="openUrl('https://github.com/levy-w-wang/lion-ui')">GitHub</el-menu-item>
</el-menu>
</div>
<!-- 右侧信息 -->
<div style="float:right">
<!-- 全屏 -->
<div style="float:left;line-height: 60px; padding: 0 10px;">
<i class="el-icon-full-screen" @click="toggleFull"></i>
</div>
<!-- 个人信息 -->
<div class="userinfo">
<el-dropdown trigger="hover">
<span class="el-dropdown-link userinfo-inner">
<img src="@assets/img/user.jpg" />
{{ userName }}<i class="el-icon-caret-bottom"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>
<router-link to="/"><i class="el-icon-s-home"></i>首页</router-link>
</el-dropdown-item>
<el-dropdown-item>
<router-link to="/"><i class="el-icon-s-custom"></i>我的主页</router-link>
</el-dropdown-item>
<el-dropdown-item divided>
<a @click="loginOut()"><i class="el-icon-switch-button"></i>登出</a>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</el-header>
<el-container>
<el-aside class="aside">
<!--导航菜单 default-active="1-1"-->
<el-menu class="el-menu-vertical-demo" :collapse="isCollapse">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-setting"></i>
<span slot="title">系统管理</span>
</template>
<el-menu-item index="1-1" @click="$router.push('usermanage')">用户管理</el-menu-item>
<el-menu-item index="1-2" @click="$router.push('menumanage')">菜单管理</el-menu-item>
</el-submenu>
<el-menu-item index="2" disabled>
<i class="el-icon-magic-stick"></i>
<span slot="title">导航一</span>
</el-menu-item>
<el-menu-item index="3" disabled>
<i class="el-icon-reading"></i>
<span slot="title">导航二</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template> <script>
import screenfull from 'screenfull'
export default {
data() {
return {
isCollapse: false,
userName: 'Levy',
}
},
//引入组件
components: {},
// 方法
methods: {
openUrl(url) {
window.open(url)
},
//折叠导航栏
collapse: function() {
this.isCollapse = !this.isCollapse
},
loginOut() {
this.$confirm('确认退出吗?', '提示', {
type: 'warning',
})
.then(() => {
this.$store.commit('logout')
})
.catch(() => {})
},
toggleFull() {
if (!screenfull.isEnabled) {
this.$message({
type: 'warning',
message: 'you browser can not work',
})
return false
}
screenfull.toggle()
},
},
// 计算属性
computed: {},
//未挂载DOM,不能访问ref为空数组
//可在这结束loading,还做一些初始化,实现函数自执行,
//可以对data数据进行操作,可进行一些请求,请求不易过多,避免白屏时间太长。
created() {},
//可在这发起后端请求,拿回数据,配合路由钩子做一些事情;可对DOM 进行操作
mounted() {},
}
</script> <style lang="scss" scoped>
.aside {
flex: 0 0 230px;
height: 100%;
.el-menu {
height: 100%;
text-align: left;
}
}
.header {
padding-left: 0px !important;
height: 60px;
line-height: 60px;
width: 100%;
background: #4b5f6e;
color: #fff;
.logo {
float: left;
height: 60px;
padding: 0;
margin: 0;
}
.logo-width {
width: 230px;
}
.logo-collapse-width {
width: 65px;
} .tools {
padding-left: 10px;
padding-right: 10px;
text-align: center;
width: 40px;
height: 60px;
line-height: 60px;
float: left;
cursor: pointer;
}
.heardNavBar {
float: left;
background: #4b5f6e;
padding: 0px 0px;
height: 60px;
line-height: 60px;
font-size: 28px;
cursor: pointer;
} .userinfo {
text-align: right;
padding-right: 24px;
float: right;
padding: 0 10px;
.userinfo-inner {
font-size: 20px;
cursor: pointer;
color: #fff;
img {
width: 40px;
height: 40px;
border-radius: 10px;
margin: 10px 0px 10px 10px;
float: right;
}
}
}
}
</style>

其中设计到了 全屏按钮 的使用,

需要执行以下安装命令:

npm install sreenfull --save

Vue管理系统前端系列三登录页和首页及`vuex`管理登录状态的更多相关文章

  1. Vue管理系统前端系列一vue-cli4.x 初始化项目

    目录 项目介绍 技术基础 开发环境 安装工具 快速原型开发 创建项目 配置相关说明 目录结构 项目介绍 lion-ui 是一个基于 RBAC 的管理系统前端项目,采用 vue 和 element-ui ...

  2. Vue管理系统前端系列六动态路由-权限管理实现

    目录 为什么要使用动态路由? 主流的两种实现方式 前端控制 后端控制 后端控制路由 实现 添加菜单接口 及 菜单状态管理 根据得到的菜单生成动态路由 根据 vuex 中的暂存的菜单生成侧边菜单栏 退出 ...

  3. Vue管理系统前端系列二相关工具引入及封装

    目录 sass-loader/vuex 等的引入说明 引入 element 引入 axios 1.基本使用 2.封装使用 2.1 开发环境配置请求地址 2.2 配置代理 2.3 添加接口相关文件 sa ...

  4. Vue管理系统前端系列四组件拆分封装

    目录 组件封装 首页布局拆分后结构 拆分后代码 状态管理中添加 app 模块 组件封装 在上一篇记录中,首页中有太多的代码,为了避免代码的臃肿,需要对主要的功能模块拆分,来让代码看起来更简洁,且能进行 ...

  5. Vue管理系统前端系列五自定义主题

    目录 自定义主题 1.安装「主题生成工具」 2.安装白垩主题 3.新建颜色挑选组件 自定义主题 1.安装「主题生成工具」 由于主题工具需要依赖于 node-sass,而node-sass版本兼容性并不 ...

  6. vue项目前端限制页面长时间未操作超时退出到登录页

    之前项目超时判断是后台根据token判断的,这样判断需要请求接口才能得到返回结果,这样就出现页面没有接口请求时还可以点击,有接口请求时才会退出 现在需要做到的效果是:页面超过30分钟未操作时,无论点击 ...

  7. 【转】手摸手,带你用vue撸后台 系列三(实战篇)

    前言 在前面两篇文章中已经把基础工作环境构建完成,也已经把后台核心的登录和权限完成了,现在手摸手,一起进入实操. Element 去年十月份开始用vue做管理后台的时候毫不犹豫的就选择了Elemen, ...

  8. Vue笔记:使用 vuex 管理应用状态

    如果你在使用 vue.js , 那么我想你可能会对 vue 组件之间的通信感到崩溃 . 我在使用基于 vue.js 2.0 的UI框架 ElementUI 开发网站的时候 , 就遇到了这种问题 : 一 ...

  9. 通过ajax前端后台交互/登录页和注册页前端后台交互详解/前端后台交互基础应用/几个后台函数的基础应用/php文件函数基础应用/php字符传函数基础应用/php数组函数基础应用

      前  言  PHP     学习了好久的PHP,今天做一个可以后台交互的登录页和注册页,没做什么判断,简单的了解一下. 具体的内容分析如下: ① PHP中的数据传输-->>由注册页传输 ...

随机推荐

  1. springboot项目部署到tomcat步骤以及常见问题

    ------------恢复内容开始------------ 本文分为两个部分,一,是打包的步骤,二,是我项目中所遇到的问题以及解决方法 一. 打包为war包步骤 1.修改打包方式为war 在pom. ...

  2. PHP 命名空间(namespace)定义

    PHP 命名空间(namespace) PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物. 不过在PHP当中还是有着相当重要的意义 ...

  3. Python Tuple(元组) min()方法

    描述 Python 元组 min() 函数返回元组中元素最小值.高佣联盟 www.cgewang.com 语法 min()方法语法: min(tuple) 参数 tuple -- 指定的元组. 返回值 ...

  4. Skill 如何翻转一个list

    https://www.cnblogs.com/yeungchie/ code 发现已经有内置了reverse(l_list) unless(fboundp('reverse) procedure(y ...

  5. SpringMVC文件上传下载(单文件、多文件)

    前言 大家好,我是bigsai,今天我们学习Springmvc的文件上传下载. 文件上传和下载是互联网web应用非常重要的组成部分,它是信息交互传输的重要渠道之一.你可能经常在网页上传下载文件,你可能 ...

  6. JavaScript Object的复制

    var obj = { a: 1, b: 2, c: { d: 3, e: 4, f: function () { console.log("对象复制"); } } } 1. fo ...

  7. CI/CD:Jenkins的流水线demo入门

    在敏捷开发或者devops中,Jenkins常常作为CI/CD的主选平台,而流水线(Pipeline)是CI/CD的一个常见的体现形式,通过流水线,我们可以配置一个从编译打包,部署,自动化测试,到产品 ...

  8. Java web Cookie详解(持久化+原理详解+共享问题+设置中文+发送多个Cookie)

    Java web Cookie详解 啥是cookie? 查询有道词典得: web和饼干有啥关系? 这个谜底等等来为大家揭晓 会话技术 web中的会话技术类似于生活中两个人聊天,不过web中的会话指的是 ...

  9. Vue 父子组件之间的互相调用方法

    第一种方法 直接在子组件中通过this.$parent.event来调用父组件的方法 父组件 <template> <div> <child></child& ...

  10. 谁来教我渗透测试——黑客必须掌握的HTML基础(一)

    小伙伴们,好几天不见了,这一周菜鸟小白工作很忙,所以没有每天更新学习内容,但是菜鸟小白的学习是没有停下来的,只是没有时间来整理学习笔记了.现在就将菜鸟小白这两天学习的HTML基础和大家分享,其中还会拿 ...