登录
1. 找到 src/router/index.js
路由文件,添加登录路由代码:
{
path: '/login',
component: (resolve) => require(['@/views/login.vue'], resolve)
}
2. 在 src/views
目录下新增 login.vue
文件,内容如下:
<template>
<div class="login-bg">
<div class="login-box">
<h2 class="login-tit">My Vue2</h2>
<el-form :model="formData" @keyup.enter.native="submit">
<el-form-item prop="userName">
<el-input v-model="formData.userName" clearable prefix-icon="el-icon-user" placeholder="请输入用户名" autofocus></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="formData.password" clearable prefix-icon="el-icon-unlock" placeholder="请输入密码" show-password></el-input>
</el-form-item>
<p>用户名密码随意填写即可!</p>
<el-button class="btn-submit" type="primary" @click="submit" :loading="loading">登 录</el-button>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
loading: false,
// 表单相关
formData: {
userName: '',
password: ''
}
}
},
mounted() {
},
methods: {
/**
* 登录
*/
submit() {
this.loading = true
this.$store.commit('SET_USER', { userName: this.formData.userName })
this.$router.replace('/home')
}
}
}
</script>
<style lang="less" scoped>
.login-bg {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #f7f7f7;
}
.login-box {
width: 400px;
padding: 20px;
background: #fff;
border-radius: 8px;
.login-tit {
margin-bottom: 20px;
text-align: center;
}
.btn-submit {
width: 100%;
}
}
</style>
以上代码实现了一个简单的登录页面,在表单中输入用户名和密码后,点击登录按钮可以进行登录操作,并跳转到系统主页。
3. 定义表单验证文件
在src/assets/scripts
目录下新增一个名为validate.js
的文件,内容如下:
export default {
// 非空 输入框
RI: { required: true, message: '请输入' },
// 非空 选择器
RS: { required: true, message: '请选择' },
// 不以空格开头或结尾
space: { pattern: /^[^\s]+(\s+[^\s]+)*$/, message: '不以空格开头或结尾' }
}
以上代码是一个验证规则的定义文件,通过导出一个对象来提供几个常用的验证规则。
这样我们就能将整个应用的验证规则都写在这个文件进行统一管理,避免后期维护时在页面组件中进行修改。
4. 在登录中使用定义的验证规则
打开之前新建的login.vue
文件,在script
中添加引入验证文件代码:
import V from '@/assets/scripts/validate'
export default {
data() {
return {
V
}
}
}
在template
模板中,将规则绑定到表单项中:
<el-form-item prop="userName" :rules="[V.RI, V.space]">
···
</el-form-item>
<el-form-item prop="password" :rules="[V.RI], V.space">
···
</el-form-item>
提交时调用验证:
submit() {
this.$refs.formData.validate((valid) => {
if (valid) {
this.loading = true
this.$store.commit('SET_USER', { userName: this.formData.userName })
this.$router.replace('/home')
}
})
}
login.vue
文件修改完成后的完整内容如下:
<template>
<div class="login-bg">
<div class="login-box">
<h2 class="login-tit">My Vue2</h2>
<el-form :model="formData" ref="formData" @keyup.enter.native="submit">
<el-form-item prop="userName" :rules="[V.RI, V.space]">
<el-input v-model="formData.userName" clearable prefix-icon="el-icon-user" placeholder="请输入用户名" autofocus></el-input>
</el-form-item>
<el-form-item prop="password" :rules="[V.RI, V.space]">
<el-input v-model="formData.password" clearable prefix-icon="el-icon-unlock" placeholder="请输入密码" show-password></el-input>
</el-form-item>
<p>用户名密码随意填写即可!</p>
<el-button class="btn-submit" type="primary" @click="submit" :loading="loading">登 录</el-button>
</el-form>
</div>
</div>
</template>
<script>
import V from '@/assets/scripts/validate'
export default {
data() {
return {
V,
loading: false,
// 表单相关
formData: {
userName: '',
password: ''
}
}
},
mounted() {
},
methods: {
/**
* 登录
*/
submit() {
this.$refs.formData.validate((valid) => {
if (valid) {
this.loading = true
this.$store.commit('SET_USER', { userName: this.formData.userName })
this.$router.replace('/home')
}
})
}
}
}
</script>
<style lang="less" scoped>
.login-bg {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #f7f7f7;
}
.login-box {
width: 400px;
padding: 20px;
background: #fff;
border-radius: 8px;
.login-tit {
margin-bottom: 20px;
text-align: center;
}
.btn-submit {
width: 100%;
}
}
</style>
这样我们一个基础的登录就完成了,其中包括了:进入页面自动聚焦到用户名输入框、密码框内容可见切换、登录表单中输入框聚焦时回车键触发提交事件、表单验证和验证成功后将输入的用户名放入Vuex用户对象中并跳转到首页。
主子界面路由嵌套
1. 在src/components
目录中新建一个目录layout
并在目录中新建一个名为wrap.vue
的文件,内容如下:
<template>
<div class="wrapper">
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
<script>
export default {
data() {
return {
}
},
mounted() {
},
methods: {
}
}
</script>
<style lang="less" scoped>
</style>
<keep-alive>
是 Vue 中的一个内置组件,用于保留组件状态并缓存组件实例。它可以在组件切换时将组件保存在内存中,以便下次再使用时不需要重新渲染和初始化组件。
在 Vue Router 配置中,可以通过嵌套多个 <router-view>
来构建复杂的页面布局。每个 <router-view>
将根据不同的路由匹配来渲染相应的组件内容,其中最外层 <router-view>
对应着根路由,而嵌套的 <router-view>
对应着子路由。
这样我们就能通过了文件中的 <router-view>
匹配渲染子路由的组件内容,从而实现主子页面的嵌套效果。
2. 新建首页页面组件
在src/views/
目录中新增一个名为home
的子目录,并在新目录下添加一个名为 index.vue
的文件,内容如下:
<template>
<div class="center">
<h2>欢迎使用!</h2>
</div>
</template>
<style lang="less" scoped>
.center {
display: grid;
place-items: center;
height: 100%;
}
</style>
3. 配置路由
在src/router/
目录中新增一个名为menus.js
的子路由文件,内容如下:
export default [
{
path: '/home',
component: (resolve) => require(['@/views/home/index.vue'], resolve),
meta: {
keepAlive: true
}
},
{
path: '/one/two',
component: (resolve) => require(['@/views/home/index.vue'], resolve)
}
// 其他菜单页面路由
]
上述代码中 meta
对象中 keepAlive
属性用于设置 wrap.vue
中 <keep-alive>
标签的缓存是否开启。
找到src/router/index.js
文件,引入wrap.vue
和menus.js
:
import wrap from '@/components/layout/wrap.vue'
import menusRouter from './menus' // 菜单路由
将原来的/home
路由配置代码改为由嵌套的结构,并将子页面路由嵌套进去,内容如下:
{
path: '/',
component: wrap,
children: menusRouter
}
src/router/index.js
路由文件修改完成后的完整代码内容如下:
import Vue from 'vue'
import VueRouter from 'vue-router'
import wrap from '@/components/layout/wrap.vue'
import menusRouter from './menus' // 菜单路由
Vue.use(VueRouter)
const pages = [
{
path: '/',
component: wrap,
children: menusRouter
},
{
path: '/login',
component: (resolve) => require(['@/views/login.vue'], resolve)
},
{
path: '/errorPage/404',
component: (resolve) => require(['@/views/404.vue'], resolve)
}
]
const router = new VueRouter({
routes: [
// 默认路由
{
path: '/',
redirect: '/home'
},
// 页面路由
...pages,
// 没有匹配的路由重定向到404页面
{
path: '*',
redirect: '/errorPage/404'
}
]
})
// 路由跳转前
router.beforeEach((to, from, next) => {
// 可用于拦截导航并执行一些操作,例如验证用户身份、权限控制等。
next()
})
// 路由跳转后
router.afterEach((to, from) => {
window.scrollTo(0, 0) // 每次路由改变滚动条都回到顶部
})
export default router
这样一个基本的主子界面路由嵌套关系就完成了,之后我们只需要在wrap.vue
中添加主界面的基本功能:菜单栏、头部导航栏、子界面显示区域。
主子界面的基本功能和样式布局
菜单栏
菜单部分我们当前应用做常规的左侧菜单栏。
1. 在layout
目录中新建一个名为menu-tree.vue
的无限菜单组件文件,内容如下:
<template>
<div class="menu-tree">
<template v-for="item in menuList">
<el-submenu :key="item.path" :index="item.path" v-if="item.children && item.children.length > 0">
<template slot="title">
<i :class="item.icon"></i>
<span slot="title">{{item.title}}</span>
</template>
<!-- 组件自调用 -->
<MenuTree :menuList="item.children"></MenuTree>
</el-submenu>
<el-menu-item :key="item.path" :index="item.path" v-else>
<i :class="item.icon"></i>
<span slot="title">{{item.title}}</span>
</el-menu-item>
</template>
</div>
</template>
<script>
export default {
name: 'MenuTree', // name 必须写用于组件自调用
props: {
// 菜单列表
menuList: {
type: Array,
default: () => []
}
}
}
</script>
2. 在layout
目录中新建一个名为menu.vue
的菜单组件文件,并在其中使用无限菜单组件,内容如下:
<template>
<div class="menu-box" :class="{'menu-collapse': isCollapse}">
<i class="collapse-icon" :class="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'" @click="isCollapse = !isCollapse"></i>
<div class="menu-logo">
<img class="logo-img" src="@img/logo.png" alt="logo">
<span class="logo-name">My Vue2</span>
</div>
<el-scrollbar>
<el-menu
:default-active="$route.path"
:collapse="isCollapse"
:collapse-transition="false"
unique-opened
router
background-color="#202123"
text-color="#fff"
active-text-color="#409EFF"
>
<MenuTree :menuList="menuList" />
</el-menu>
</el-scrollbar>
</div>
</template>
<script>
import MenuTree from './menu-tree.vue'
export default {
components: { MenuTree }, // 组件
data() {
return {
isCollapse: false,
menuList: [
{
path: '/home',
title: '首页',
icon: 'el-icon-s-home'
},
{
path: '/one',
title: '一级页面',
icon: 'el-icon-menu',
children: [
{
path: '/one/two',
title: '二级页面'
}
]
}
]
}
},
methods: {
}
}
</script>
<style lang="less" scoped>
.menu-box {
position: relative;
flex-shrink: 0;
width: 300px;
background: #202123;
transition: width .3s;
&.menu-collapse {
width: 64px;
.logo-name {
display: none;
}
/deep/ .el-submenu__title span {
display: none;
}
}
.collapse-icon {
position: absolute;
right: -30px;
top: 15px;
font-size: 30px;
color: #fff;
}
.menu-logo {
display: flex;
align-items: center;
padding: 0 15px;
height: 60px;
color: #fff;
font-size: 20px;
white-space: nowrap;
overflow: hidden;
.logo-img {
margin-right: 10px;
height: 30px;
}
}
.el-scrollbar {
height: calc(100% - 60px);
/deep/ .el-scrollbar__wrap {
overflow-x: hidden;
}
}
.el-menu {
border: 0;
}
}
</style>
3. 在wrap.vue
中引用组件并使用:
引入菜单组件
import Menu from './menu.vue'
注册组件
components: { Menu }, // 组件
template
中使用组件
<Menu/>
wrap.vue
修改后的完整内容如下:
<template>
<div class="wrapper">
<Menu />
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
<script>
import Menu from './menu.vue'
export default {
components: { Menu }, // 组件
data() {
return {
}
},
mounted() {
},
methods: {
}
}
</script>
<style lang="less" scoped>
</style>
头部导航栏
1. 在 layout
目录下新建一个名为 header.vue
的头部导航栏组件,内容如下:
<template>
<div class="header-box">
</div>
</template>
<script>
export default {
data() {
},
methods: {
}
}
</script>
<style lang="less" scoped>
</style>
2. 在wrap.vue
中引用组件并使用:
引入菜单组件
import Header from './header.vue'
注册组件
components: { Header }, // 组件
template
中使用组件,并修改菜单组件、头部组件、子界面容器的代码结构:
<template>
<div class="wrapper">
<Menu />
<div class="header-subpage-content">
<Header />
<div class="subpage-content">
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</div>
</div>
</template>
添加主子界面布局样式
.wrapper {
display: flex;
width: 100%;
height: 100vh;
.header-subpage-content {
display: flex;
flex-direction: column;
width: 100%;
.subpage-content {
height: 100%;
}
}
}
wrap.vue
修改后的完整内容如下:
<template>
<div class="wrapper">
<Menu />
<div class="header-subpage-content">
<Header />
<div class="subpage-content">
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</div>
</div>
</template>
<script>
import Menu from './menu.vue'
import Header from './header.vue'
export default {
components: { Menu, Header }, // 组件
data() {
return {
}
},
mounted() {
},
methods: {
}
}
</script>
<style lang="less" scoped>
.wrapper {
display: flex;
width: 100%;
height: 100vh;
.header-subpage-content {
display: flex;
flex-direction: column;
width: 100%;
.subpage-content {
height: 100%;
}
}
}
</style>
3. 用户基本操作模块(用户头像、用户名、退出登录)
将 header.vue
中内容替换为以下内容:
<template>
<div class="header-box">
<el-dropdown class="user-dropdown" @command="handleUser">
<img class="user-pic" src="@img/pic.png" />
<el-dropdown-menu slot="dropdown">
<el-dropdown-item disabled>{{ $store.getters.GET_USER.userName }}</el-dropdown-item>
<el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
/**
* 用户相关操作
* @param {String} functionName 函数名称
*/
handleUser(functionName) {
this[functionName]()
},
/**
* 退出登录
*/
logout() {
this.$router.replace('/login')
}
}
}
</script>
<style lang="less" scoped>
.header-box {
min-height: 60px;
color: #fff;
background: #202123;
.user-dropdown {
float: right;
display: flex;
align-items: center;
margin-right: 10px;
height: 100%;
color: #fff;
cursor: pointer;
.user-pic {
width: 40px;
height: 40px;
}
}
}
</style>
到这里整个后台管理系统的基本主框架页面就完成了,后续再根据自己的添加或修改内容。
框架搭建整体流程
-
第一步 Vue2 使用 Vue 脚手架 Vue CLI 搭建一个 Vue.js 前端项目框架
-
第二步 Vue2 vue.config.js 基础配置,路径别名alias
-
第三步 Vue2 vue.config.js 集成 Less 配置 sourceMap+全局变量
-
第四步 Vue2 配置ESLint
-
第五步 Vue2 vue.config.js 使用image-minimizer-webpack-plugin配置图片压缩
-
第六步 Vue2 集成全家桶 vue-router vuex axios 和 element-ui
-
第七步 Webpack 配置多环境和全局变量 cross-env 和 webpack.DefinePlugin