登錄
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="請(qǐng)輸入用戶名" autofocus></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="formData.password" clearable prefix-icon="el-icon-unlock" placeholder="請(qǐng)輸入密碼" show-password></el-input>
</el-form-item>
<p>用戶名密碼隨意填寫(xiě)即可盟步!</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>
以上代碼實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的登錄頁(yè)面,在表單中輸入用戶名和密碼后躏结,點(diǎn)擊登錄按鈕可以進(jìn)行登錄操作却盘,并跳轉(zhuǎn)到系統(tǒng)主頁(yè)。
3. 定義表單驗(yàn)證文件
在src/assets/scripts
目錄下新增一個(gè)名為validate.js
的文件媳拴,內(nèi)容如下:
export default {
// 非空 輸入框
RI: { required: true, message: '請(qǐng)輸入' },
// 非空 選擇器
RS: { required: true, message: '請(qǐng)選擇' },
// 不以空格開(kāi)頭或結(jié)尾
space: { pattern: /^[^\s]+(\s+[^\s]+)*$/, message: '不以空格開(kāi)頭或結(jié)尾' }
}
以上代碼是一個(gè)驗(yàn)證規(guī)則的定義文件黄橘,通過(guò)導(dǎo)出一個(gè)對(duì)象來(lái)提供幾個(gè)常用的驗(yàn)證規(guī)則。
這樣我們就能將整個(gè)應(yīng)用的驗(yàn)證規(guī)則都寫(xiě)在這個(gè)文件進(jìn)行統(tǒng)一管理屈溉,避免后期維護(hù)時(shí)在頁(yè)面組件中進(jìn)行修改塞关。
4. 在登錄中使用定義的驗(yàn)證規(guī)則
打開(kāi)之前新建的login.vue
文件,在script
中添加引入驗(yàn)證文件代碼:
import V from '@/assets/scripts/validate'
export default {
data() {
return {
V
}
}
}
在template
模板中子巾,將規(guī)則綁定到表單項(xiàng)中:
<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>
提交時(shí)調(diào)用驗(yàn)證:
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="請(qǐng)輸入用戶名" 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="請(qǐng)輸入密碼" show-password></el-input>
</el-form-item>
<p>用戶名密碼隨意填寫(xiě)即可描孟!</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>
這樣我們一個(gè)基礎(chǔ)的登錄就完成了驶睦,其中包括了:進(jìn)入頁(yè)面自動(dòng)聚焦到用戶名輸入框、密碼框內(nèi)容可見(jiàn)切換匿醒、登錄表單中輸入框聚焦時(shí)回車(chē)鍵觸發(fā)提交事件、表單驗(yàn)證和驗(yàn)證成功后將輸入的用戶名放入Vuex用戶對(duì)象中并跳轉(zhuǎn)到首頁(yè)缠导。
主子界面路由嵌套
1. 在src/components
目錄中新建一個(gè)目錄layout
并在目錄中新建一個(gè)名為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 中的一個(gè)內(nèi)置組件,用于保留組件狀態(tài)并緩存組件實(shí)例僻造。它可以在組件切換時(shí)將組件保存在內(nèi)存中憋他,以便下次再使用時(shí)不需要重新渲染和初始化組件。
在 Vue Router 配置中髓削,可以通過(guò)嵌套多個(gè) <router-view>
來(lái)構(gòu)建復(fù)雜的頁(yè)面布局竹挡。每個(gè) <router-view>
將根據(jù)不同的路由匹配來(lái)渲染相應(yīng)的組件內(nèi)容,其中最外層 <router-view>
對(duì)應(yīng)著根路由立膛,而嵌套的 <router-view>
對(duì)應(yīng)著子路由揪罕。
這樣我們就能通過(guò)了文件中的 <router-view>
匹配渲染子路由的組件內(nèi)容,從而實(shí)現(xiàn)主子頁(yè)面的嵌套效果宝泵。
2. 新建首頁(yè)頁(yè)面組件
在src/views/
目錄中新增一個(gè)名為home
的子目錄好啰,并在新目錄下添加一個(gè)名為 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/
目錄中新增一個(gè)名為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)
}
// 其他菜單頁(yè)面路由
]
上述代碼中 meta
對(duì)象中 keepAlive
屬性用于設(shè)置 wrap.vue
中 <keep-alive>
標(biāo)簽的緩存是否開(kāi)啟。
找到src/router/index.js
文件闯捎,引入wrap.vue
和menus.js
:
import wrap from '@/components/layout/wrap.vue'
import menusRouter from './menus' // 菜單路由
將原來(lái)的/home
路由配置代碼改為由嵌套的結(jié)構(gòu)椰弊,并將子頁(yè)面路由嵌套進(jìn)去,內(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: [
// 默認(rèn)路由
{
path: '/',
redirect: '/home'
},
// 頁(yè)面路由
...pages,
// 沒(méi)有匹配的路由重定向到404頁(yè)面
{
path: '*',
redirect: '/errorPage/404'
}
]
})
// 路由跳轉(zhuǎn)前
router.beforeEach((to, from, next) => {
// 可用于攔截導(dǎo)航并執(zhí)行一些操作瓤鼻,例如驗(yàn)證用戶身份秉版、權(quán)限控制等。
next()
})
// 路由跳轉(zhuǎn)后
router.afterEach((to, from) => {
window.scrollTo(0, 0) // 每次路由改變滾動(dòng)條都回到頂部
})
export default router
這樣一個(gè)基本的主子界面路由嵌套關(guān)系就完成了娱仔,之后我們只需要在wrap.vue
中添加主界面的基本功能:菜單欄沐飘、頭部導(dǎo)航欄、子界面顯示區(qū)域牲迫。
主子界面的基本功能和樣式布局
菜單欄
菜單部分我們當(dāng)前應(yīng)用做常規(guī)的左側(cè)菜單欄耐朴。
1. 在layout
目錄中新建一個(gè)名為menu-tree.vue
的無(wú)限菜單組件文件,內(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 必須寫(xiě)用于組件自調(diào)用
props: {
// 菜單列表
menuList: {
type: Array,
default: () => []
}
}
}
</script>
2. 在layout
目錄中新建一個(gè)名為menu.vue
的菜單組件文件盹憎,并在其中使用無(wú)限菜單組件筛峭,內(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: '首頁(yè)',
icon: 'el-icon-s-home'
},
{
path: '/one',
title: '一級(jí)頁(yè)面',
icon: 'el-icon-menu',
children: [
{
path: '/one/two',
title: '二級(jí)頁(yè)面'
}
]
}
]
}
},
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'
注冊(cè)組件
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
目錄下新建一個(gè)名為 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'
注冊(cè)組件
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>
到這里整個(gè)后臺(tái)管理系統(tǒng)的基本主框架頁(yè)面就完成了疤祭,后續(xù)再根據(jù)自己的添加或修改內(nèi)容。
框架搭建整體流程
-
第一步 Vue2 使用 Vue 腳手架 Vue CLI 搭建一個(gè) Vue.js 前端項(xiàng)目框架
-
第二步 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