該節記錄了登陸界面的設計,以及 vuex 的簡單實用,而後將首頁簡單搭建完成。css
先看最終效果圖html
先在 views 文件夾下 新建 login/index.vue 文件。用於登陸首頁vue
vuex
相關介紹可參考另外一篇博文,連接git
新建 store/modules/user.js
,將登陸狀態及內容保存到狀態管理器中,內容以下:github
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 模塊引入進來,代碼以下:web
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 組件,進行設計登陸界面。界面代碼以下:vuex
<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>
登陸相關 腳本 代碼以下:npm
<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>
相關接口上一篇文章中有寫,這裏就再也不贅述了。api
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
原文地址:http://book.levy.net.cn/doc/frontend/uiframe/login_home.html