登錄
1. 找到 src/router/index.js
路由文件,添加登錄路由代碼:
{
path: '/login',
component: (resolve) => require(['@/views/login.vue'], resolve)
}
2. 在 src/views
目錄下新增 login.vue
文件,內(nèi)容如下:
<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,
// 表單相關(guān)
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>
以上代碼實現(xiàn)了一個簡單的登錄頁面,在表單中輸入用戶名和密碼后,點擊登錄按鈕可以進行登錄操作,并跳轉(zhuǎn)到系統(tǒng)主頁。
3. 定義表單驗證文件
在src/assets/scripts
目錄下新增一個名為validate.js
的文件,內(nèi)容如下:
export default {
// 非空 輸入框
RI: { required: true, message: '請輸入' },
// 非空 選擇器
RS: { required: true, message: '請選擇' },
// 不以空格開頭或結(jié)尾
space: { pattern: /^[^\s]+(\s+[^\s]+)*$/, message: '不以空格開頭或結(jié)尾' }
}
以上代碼是一個驗證規(guī)則的定義文件,通過導(dǎo)出一個對象來提供幾個常用的驗證規(guī)則。
這樣我們就能將整個應(yīng)用的驗證規(guī)則都寫在這個文件進行統(tǒng)一管理,避免后期維護時在頁面組件中進行修改。
4. 在登錄中使用定義的驗證規(guī)則
打開之前新建的login.vue
文件,在script
中添加引入驗證文件代碼:
import V from '@/assets/scripts/validate'
export default {
data() {
return {
V
}
}
}
在template
模板中,將規(guī)則綁定到表單項中:
<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>
提交時調(diào)用驗證:
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
文件修改完成后的完整內(nèi)容如下:
<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,
// 表單相關(guān)
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>
這樣我們一個基礎(chǔ)的登錄就完成了,其中包括了:進入頁面自動聚焦到用戶名輸入框、密碼框內(nèi)容可見切換、登錄表單中輸入框聚焦時回車鍵觸發(fā)提交事件、表單驗證和驗證成功后將輸入的用戶名放入Vuex用戶對象中并跳轉(zhuǎn)到首頁。
主子界面路由嵌套
1. 在src/components
目錄中新建一個目錄layout
并在目錄中新建一個名為wrap.vue
的文件,內(nèi)容如下:
<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 中的一個內(nèi)置組件,用于保留組件狀態(tài)并緩存組件實例。它可以在組件切換時將組件保存在內(nèi)存中,以便下次再使用時不需要重新渲染和初始化組件。
在 Vue Router 配置中,可以通過嵌套多個 <router-view>
來構(gòu)建復(fù)雜的頁面布局。每個 <router-view>
將根據(jù)不同的路由匹配來渲染相應(yīng)的組件內(nèi)容,其中最外層 <router-view>
對應(yīng)著根路由,而嵌套的 <router-view>
對應(yīng)著子路由。
這樣我們就能通過了文件中的 <router-view>
匹配渲染子路由的組件內(nèi)容,從而實現(xiàn)主子頁面的嵌套效果。
2. 新建首頁頁面組件
在src/views/
目錄中新增一個名為home
的子目錄,并在新目錄下添加一個名為 index.vue
的文件,內(nèi)容如下:
<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
的子路由文件,內(nèi)容如下:
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
屬性用于設(shè)置 wrap.vue
中 <keep-alive>
標簽的緩存是否開啟。
找到src/router/index.js
文件,引入wrap.vue
和menus.js
:
import wrap from '@/components/layout/wrap.vue'
import menusRouter from './menus' // 菜單路由
將原來的/home
路由配置代碼改為由嵌套的結(jié)構(gòu),并將子頁面路由嵌套進去,內(nèi)容如下:
{
path: '/',
component: wrap,
children: menusRouter
}
src/router/index.js
路由文件修改完成后的完整代碼內(nèi)容如下:
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'
}
]
})
// 路由跳轉(zhuǎn)前
router.beforeEach((to, from, next) => {
// 可用于攔截導(dǎo)航并執(zhí)行一些操作,例如驗證用戶身份、權(quán)限控制等。
next()
})
// 路由跳轉(zhuǎn)后
router.afterEach((to, from) => {
window.scrollTo(0, 0) // 每次路由改變滾動條都回到頂部
})
export default router
這樣一個基本的主子界面路由嵌套關(guān)系就完成了,之后我們只需要在wrap.vue
中添加主界面的基本功能:菜單欄、頭部導(dǎo)航欄、子界面顯示區(qū)域。
主子界面的基本功能和樣式布局
菜單欄
菜單部分我們當前應(yīng)用做常規(guī)的左側(cè)菜單欄。
1. 在layout
目錄中新建一個名為menu-tree.vue
的無限菜單組件文件,內(nèi)容如下:
<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>
<!-- 組件自調(diào)用 -->
<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 必須寫用于組件自調(diào)用
props: {
// 菜單列表
menuList: {
type: Array,
default: () => []
}
}
}
</script>
2. 在layout
目錄中新建一個名為menu.vue
的菜單組件文件,并在其中使用無限菜單組件,內(nèi)容如下:
<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
修改后的完整內(nèi)容如下:
<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>
頭部導(dǎo)航欄
1. 在 layout
目錄下新建一個名為 header.vue
的頭部導(dǎo)航欄組件,內(nèi)容如下:
<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
中使用組件,并修改菜單組件、頭部組件、子界面容器的代碼結(jié)構(gòu):
<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
修改后的完整內(nèi)容如下:
<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
中內(nèi)容替換為以下內(nèi)容:
<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: {
/**
* 用戶相關(guān)操作
* @param {String} functionName 函數(shù)名稱
*/
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>
到這里整個后臺管理系統(tǒng)的基本主框架頁面就完成了,后續(xù)再根據(jù)自己的添加或修改內(nèi)容。
框架搭建整體流程
-
第一步 Vue2 使用 Vue 腳手架 Vue CLI 搭建一個 Vue.js 前端項目框架
-
第二步 Vue2 vue.config.js 基礎(chǔ)配置,路徑別名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 配置多環(huán)境和全局變量 cross-env 和 webpack.DefinePlugin