目录
前言
登录页面
后台界面
前言
今天用Vue实现一个简易的后台,不借助接口和后端代码,仅通过前端实现,本案例涉及Vue路由相关知识,不熟悉Vue路由可以先看一下右边的文章再接着看下面的项目案例:Vue路由 这篇文章详细介绍了路由的知识;Vue导航 这篇文章详细介绍了路由导航的知识。
登录页面
登录页面的话不需要很复杂的逻辑,只需要写好页面的样式即可,因为账号密码没有借助后端代码来实现,只通过前端的代码实现,这一点不是很安全,因为在页面的控制台就能看到你的登录的账号密码,因为这仅是一个案例,所以就没有那么严谨了。
因为要借助Vue的路由,所以我们要先安装一下vue-router,安装完成之后,创建router文件夹,书写以下四步骤进行vue的路由调用。
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const router = new VueRouter()
export default router
创建完成后在main.js文件中引入
import router from '@/router'
login.vue代码如下:
<template>
<div class="login-container">
<div class="login-box">
<!-- 头像区域 -->
<div class="text-center avatar-box">
<img src="../assets/logo.png" class="img-thumbnail avatar" alt="">
</div>
<!-- 表单区域 -->
<div class="form-login p-4">
<!-- 登录名称 -->
<div class="form-group form-inline">
<label for="username">登录名称</label>
<input type="text"
class="form-control m1-2"
id="username"
placeholder="请输入登录名称"
autocomplete="off"
v-model.trim="username"
>
</div>
<!-- 登录密码 -->
<div class="form-group form-inline">
<label for="password">登录密码</label>
<input type="password"
class="form-control m1-2"
id="password"
placeholder="请输入密码"
v-model.trim="password"
>
</div>
<!-- 登录和重置按钮 -->
<div class="form-group form-inline d-flex justify-content-end">
<button type="button" class="btn btn-danger mr-2" @click="reset">重置</button>
<button type="button" class="btn btn-primary" @click="login">登录</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:'MyLogin',
data(){
return {
username:'',
password:''
}
},
methods:{
reset(){
this.username='',
this.password=''
},
login(){
if(this.username==='admin'&&this.password==='666666'){
// 登录成功
// 1.存储 token
localStorage.setItem('token','Bearer xxxxx')
// 2.跳转到后台主页
this.$router.push('/home')
}else{
// 登录失败
localStorage.removeItem('token')
}
}
}
}
</script>
<style lang="less" scoped>
.login-container{
background-color: #35495e;
height: 760px;
.login-box{
width: 400px;
height: 250px;
text-align: center;
background-color: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
box-shadow: 0 0 6px rgba(255,255,255,0.5);
.form-login{
position: absolute;
bottom: -15px;
left: 0;
width: 100%;
box-sizing: border-box;
#username{
width: 250px;
margin-left: 20px;
}
#password{
width: 250px;
margin-left: 20px;
}
}
.d-flex{
margin-left: 220px;
}
}
}
.form-control{
flex: 1;
}
.avatar-box {
position: absolute;
width: 100%;
top: -65px;
left: 0;
.avatar {
width: 120px;
height: 120px;
border-radius: 50% !important;
box-shadow: 0 0 6px #efefef;
}
}
</style>
当我们输入正确的账号密码后,路由跳转到我们规定的 home hash地址下, 路由规则在router文件夹下书写。
全局前置守卫为了防止在不输入账号密码的情况下,直接访问home页面就进入的情况。
import Vue from 'vue'
import VueRouter from 'vue-router'
// 导入需要的组件
import Login from '@/admin/MyLogin.vue'
import Home from '@/admin/MyHome.vue'
Vue.use(VueRouter)
const router = new VueRouter({
routes:[
// 登录的路由规则
{path:'/',redirect:'/login'},
{path:'/login',component:Login},
{path:'/home',component:Home,}
]
})
// 全局前置守卫
router.beforeEach(function(to,from,next){
const pathArr = ['/home']
if(pathArr.indexOf(to.path)!=-1){
const token = localStorage.getItem('token')
if(token){
next()
}else{
next('/login')
}
}else{
next()
}
})
export default router
后台界面
接下来要准备给后台添加一些内容,如下:
Home组件内容如下:
<template>
<div class="home-container">
<!-- 头部区域 -->
<MyHeader></MyHeader>
<!-- 页面主体区域 -->
<div class="home-main-box">
<!-- 左侧边栏 -->
<MyAside></MyAside>
<!-- 右侧内容主题区域 -->
<div class="home-main-body">
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
import MyHeader from '@/admin/subcomponents/MyHeader.vue'
import MyAside from '@/admin/subcomponents/MyAside.vue'
export default {
components:{
MyHeader,MyAside
}
}
</script>
<style lang="less" scoped>
.home-container {
height: 100%;
display: flex;
flex-direction: column;
.home-main-box {
height: 100%;
display: flex;
.home-main-body {
padding: 15px;
flex: 1;
}
}
}
</style>
给后台页面匹配路由规程,如下:
import Vue from 'vue'
import VueRouter from 'vue-router'
// 导入需要的组件
import Login from '@/admin/MyLogin.vue'
import Home from '@/admin/MyHome.vue'
// 导入子组件路由
import Users from '@/admin/menus/MyUsers.vue'
import Rights from '@/admin/menus/MyRight.vue'
import Goods from '@/admin/menus/MyGoods.vue'
import Orders from '@/admin/menus/MyOrders.vue'
import Settings from '@/admin/menus/MySettings.vue'
import UserDetail from '@/admin/user/MyUserDetail.vue'
Vue.use(VueRouter)
const router = new VueRouter({
routes:[
// 登录的路由规则
{path:'/',redirect:'/login'},
{path:'/login',component:Login},
{path:'/home',redirect:'/home/users',component:Home,children:[
{path:'users',component:Users},
{path:'rights',component:Rights},
{path:'goods',component:Goods},
{path:'orders',component:Orders},
{path:'settings',component:Settings},
// 用户详情页的路由规则
{path:'userinfo/:id',component:UserDetail,props:true}
]}
]
})
// 全局前置守卫
router.beforeEach(function(to,from,next){
const pathArr = ['/home','/home/users','home/rights']
if(pathArr.indexOf(to.path)!=-1){
const token = localStorage.getItem('token')
if(token){
next()
}else{
next('/login')
}
}else{
next()
}
})
export default router
书写头部组件,如下:
<template>
<div class="layout-header-container d-flex justify-content-between align-items-center p-3">
<!-- 左侧 logo 和 标题区域 -->
<div class="layout-header-left d-flex align-items-center user-select-none">
<!-- logo -->
<img class="layout-header-left-img" src="../../assets/logo.png" alt="" />
<!-- 标题 -->
<h4 class="layout-header-left-title ml-3">后台管理系统</h4>
</div>
<!-- 右侧按钮区域 -->
<div class="layout-header-right">
<button type="button" class="btn btn-light" @click="logout">退出登录</button>
</div>
</div>
</template>
<script>
export default {
name: 'MyHeader',
methods: {
logout() {
// 1. 清空 token
localStorage.removeItem('token')
// 2. 跳转到登录页面
this.$router.push('/login')
}
}
}
</script>
<style lang="less" scoped>
.layout-header-container {
height: 60px;
border-bottom: 1px solid #eaeaea;
}
.layout-header-left-img {
height: 50px;
}
</style>
书写左侧边栏,如下:
<template>
<div class="layout-aside-container">
<!-- 左侧边栏列表 -->
<ul class="user-select-none menu">
<li class="menu-item">
<router-link to="/home/users">用户管理</router-link>
</li>
<li class="menu-item">
<router-link to="/home/rights">权限管理</router-link>
</li>
<li class="menu-item">
<router-link to="/home/goods">商品管理</router-link>
</li>
<li class="menu-item">
<router-link to="/home/orders">订单管理</router-link>
</li>
<li class="menu-item">
<router-link to="/home/settings">系统管理</router-link>
</li>
</ul>
</div>
</template>
<script>
export default {
name:'MyAside'
}
</script>
<style lang="less" scoped>
.layout-aside-container{
width: 250px;
height: 700px;
border-right: 1px solid #eaeaea;
}
.menu{
list-style: none;
padding: 0;
.menu-item{
line-height: 50px;
font-weight: bold;
font-size: 14px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
&:hover{
background-color: #efefef;
cursor: pointer;
}
a{
display: block;
color: black;
padding-left: 30px;
&:hover{
text-decoration: none;
}
}
}
}
// 设置路由高亮效果
.router-link-active{
background-color: #efefef;
box-sizing: border-box;
position: relative;
// 伪元素实现路由高亮效果
&::before{
content: '';
display: block;
width: 4px;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-color: #42b983;
}
}
</style>
上文的路由规则已经书写了home组件下子路由的规则,点击侧边栏的菜单直接进入子路由的路径
users子组件的内容如下:
<template>
<div>
<!-- 标题 -->
<h4 class="text-center">用户管理</h4>
<!-- 用户列表 -->
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>头衔</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in userlist" :key="item.id">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
<td>{{item.position}}</td>
<td><a href="#" @click.prevent="gotoDetail(item.id)">详情</a></td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data(){
return {
// 用户列表
userlist:[
{id:1,name:'张三',age:18,position:'律师'},
{id:2,name:'李四',age:28,position:'老师'},
{id:3,name:'王五',age:33,position:'工程师'},
{id:4,name:'陈六',age:23,position:'商人'},
]
}
},
methods:{
gotoDetail(id){
this.$router.push('/home/userinfo/'+id)
}
}
}
</script>
<style>
</style>
每天一个小案例,让自己的代码水平趋于成熟。