今日目標(biāo)
1.實(shí)現(xiàn)后臺(tái)首頁(yè)的基本布局
2.實(shí)現(xiàn)左側(cè)菜單欄
3.實(shí)現(xiàn)用戶列表展示
4.實(shí)現(xiàn)添加用戶
1.后臺(tái)首頁(yè)基本布局
打開(kāi)Home.vue組件盈简,進(jìn)行布局:
<el-container class="home-container">
<!-- 頭部區(qū)域 -->
<el-header>Header<el-button type="info" @click="logout"> 退出 </el-button></el-header>
<!-- 頁(yè)面主體區(qū)域 -->
<el-container>
<!-- 側(cè)邊欄 -->
<el-aside width="200px">Aside</el-aside>
<!-- 主體結(jié)構(gòu) -->
<el-main>Main</el-main>
</el-container>
</el-container>
默認(rèn)情況下公般,跟element-ui組件同名的類(lèi)名可以幫助我們快速的給對(duì)應(yīng)的組件添加樣式,如:
.home-container {
height: 100%;
}
.el-header{
background-color:#373D41;
}
.el-aside{
background-color:#333744;
}
.el-main{
background-color:#eaedf1;
}
2.頂部布局,側(cè)邊欄布局
<template>
<el-container class="home-container">
<!-- 頭部區(qū)域 -->
<el-header>
<div>
<!-- 黑馬logo -->
<img src="../assets/heima.png" alt="">
<!-- 頂部標(biāo)題 -->
<span>電商后臺(tái)管理系統(tǒng)</span>
</div>
<el-button type="info" @click="logout"> 退出 </el-button>
</el-header>
<!-- 頁(yè)面主體區(qū)域 -->
<el-container>
<!-- 側(cè)邊欄 -->
<el-aside width="200px">
<!-- 側(cè)邊欄菜單 -->
<el-menu
background-color="#333744"
text-color="#fff"
active-text-color="#ffd04b">
<!-- 一級(jí)菜單 -->
<el-submenu index="1">
<!-- 一級(jí)菜單模板 -->
<template slot="title">
<!-- 圖標(biāo) -->
<i class="el-icon-location"></i>
<!-- 文本 -->
<span>導(dǎo)航一</span>
</template>
<!-- 二級(jí)子菜單 -->
<el-menu-item index="1-4-1">
<!-- 二級(jí)菜單模板 -->
<template slot="title">
<!-- 圖標(biāo) -->
<i class="el-icon-location"></i>
<!-- 文本 -->
<span>子菜單一</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<!-- 主體結(jié)構(gòu) -->
<el-main>Main</el-main>
</el-container>
</el-container>
</template>
3.axios請(qǐng)求攔截器
后臺(tái)除了登錄接口之外,都需要token權(quán)限驗(yàn)證,我們可以通過(guò)添加axios請(qǐng)求攔截器來(lái)添加token市咆,以保證擁有獲取數(shù)據(jù)的權(quán)限
在main.js中添加代碼,在將axios掛載到vue原型之前添加下面的代碼
//請(qǐng)求在到達(dá)服務(wù)器之前再来,先會(huì)調(diào)用use中的這個(gè)回調(diào)函數(shù)來(lái)添加請(qǐng)求頭信息
axios.interceptors.request.use(config=>{
//為請(qǐng)求頭對(duì)象蒙兰,添加token驗(yàn)證的Authorization字段
config.headers.Authorization = window.sessionStorage.getItem("token")
return config
})
4.請(qǐng)求側(cè)邊欄數(shù)據(jù)
<script>
export default {
data() {
return {
// 左側(cè)菜單數(shù)據(jù)
menuList: null
}
},
created() {
// 在created階段請(qǐng)求左側(cè)菜單數(shù)據(jù)
this.getMenuList()
},
methods: {
logout() {
window.sessionStorage.clear()
this.$router.push('/login')
},
async getMenuList() {
// 發(fā)送請(qǐng)求獲取左側(cè)菜單數(shù)據(jù)
const { data: res } = await this.$http.get('menus')
if (res.meta.status !== 200) return this.$message.error(res.meta.msg)
this.menuList = res.data
console.log(res)
}
}
}
</script>
通過(guò)v-for雙重循環(huán)渲染左側(cè)菜單
<el-menu
background-color="#333744"
text-color="#fff"
active-text-color="#ffd04b">
<!-- 一級(jí)菜單 -->
<el-submenu :index="item.id+''" v-for="item in menuList" :key="item.id">
<!-- 一級(jí)菜單模板 -->
<template slot="title">
<!-- 圖標(biāo) -->
<i class="el-icon-location"></i>
<!-- 文本 -->
<span>{{item.authName}}</span>
</template>
<!-- 二級(jí)子菜單 -->
<el-menu-item :index="subItem.id+''" v-for="subItem in item.children" :key="subItem.id">
<!-- 二級(jí)菜單模板 -->
<template slot="title">
<!-- 圖標(biāo) -->
<i class="el-icon-location"></i>
<!-- 文本 -->
<span>{{subItem.authName}}</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
5.設(shè)置激活子菜單樣式
通過(guò)更改el-menu的active-text-color屬性可以設(shè)置側(cè)邊欄菜單中點(diǎn)擊的激活項(xiàng)的文字顏色
通過(guò)更改菜單項(xiàng)模板(template)中的i標(biāo)簽的類(lèi)名,可以將左側(cè)菜單欄的圖標(biāo)進(jìn)行設(shè)置芒篷,我們需要在項(xiàng)目中使用第三方字體圖標(biāo)
在數(shù)據(jù)中添加一個(gè)iconsObj:
iconsObj: {
'125':'iconfont icon-user',
'103':'iconfont icon-tijikongjian',
'101':'iconfont icon-shangpin',
'102':'iconfont icon-danju',
'145':'iconfont icon-baobiao'
}
然后將圖標(biāo)類(lèi)名進(jìn)行數(shù)據(jù)綁定搜变,綁定iconsObj中的數(shù)據(jù):
為了保持左側(cè)菜單每次只能打開(kāi)一個(gè),顯示其中的子菜單针炉,我們可以在el-menu中添加一個(gè)屬性u(píng)nique-opened
或者也可以數(shù)據(jù)綁定進(jìn)行設(shè)置(此時(shí)true認(rèn)為是一個(gè)bool值挠他,而不是字符串) :unique-opened="true"
6.制作側(cè)邊菜單欄的伸縮功能
在菜單欄上方添加一個(gè)div
<!-- 側(cè)邊欄,寬度根據(jù)是否折疊進(jìn)行設(shè)置 -->
<el-aside :width="isCollapse ? '64px':'200px'">
<!-- 伸縮側(cè)邊欄按鈕 -->
<div class="toggle-button" @click="toggleCollapse">|||</div>
<!-- 側(cè)邊欄菜單,:collapse="isCollapse"(設(shè)置折疊菜單為綁定的 isCollapse 值)篡帕,:collapse-transition="false"(關(guān)閉默認(rèn)的折疊動(dòng)畫(huà)) -->
<el-menu
:collapse="isCollapse"
:collapse-transition="false"
......
然后給div添加樣式殖侵,給div添加事件:
<div class="toggle-button" @click="this.isCollapse ? '64px':'200px'">|||</div>
7.在后臺(tái)首頁(yè)添加子級(jí)路由
新增子級(jí)路由組件Welcome.vue
在router.js中導(dǎo)入子級(jí)路由組件,并設(shè)置路由規(guī)則以及子級(jí)路由的默認(rèn)重定向
打開(kāi)Home.vue镰烧,在main的主體結(jié)構(gòu)中添加一個(gè)路由占位符
制作好了Welcome子級(jí)路由之后拢军,我們需要將所有的側(cè)邊欄二級(jí)菜單都改造成子級(jí)路由鏈接
我們只需要將el-menu的router屬性設(shè)置為true就可以了,此時(shí)當(dāng)我們點(diǎn)擊二級(jí)菜單的時(shí)候怔鳖,就會(huì)根據(jù)菜單的index
屬性進(jìn)行路由跳轉(zhuǎn),如: /110,
使用index id來(lái)作為跳轉(zhuǎn)的路徑不合適茉唉,我們可以重新綁定index的值為 :index="'/'+subItem.path"
8.完成用戶列表主體區(qū)域
新建用戶列表組件 user/Users.vue
在router.js中導(dǎo)入子級(jí)路由組件Users.vue,并設(shè)置路由規(guī)則
當(dāng)點(diǎn)擊二級(jí)菜單的時(shí)候,被點(diǎn)擊的二級(jí)子菜單并沒(méi)有高亮赌渣,我們需要正在被使用的功能高亮顯示
我們可以通過(guò)設(shè)置el-menu的default-active屬性來(lái)設(shè)置當(dāng)前激活菜單的index
但是default-active屬性也不能寫(xiě)死魏铅,固定為某個(gè)菜單值
所以我們可以先給所有的二級(jí)菜單添加點(diǎn)擊事件,并將path值作為方法的參數(shù)
@click="saveNavState('/'+subItem.path)"
在saveNavState方法中將path保存到sessionStorage中
saveNavState( path ){
//點(diǎn)擊二級(jí)菜單的時(shí)候保存被點(diǎn)擊的二級(jí)菜單信息
window.sessionStorage.setItem("activePath",path);
this.activePath = path;
}
然后在數(shù)據(jù)中添加一個(gè)activePath綁定數(shù)據(jù)昌犹,并將el-menu的default-active屬性設(shè)置為activePath
最后在created中將sessionStorage中的數(shù)據(jù)賦值給activePath
this.activePath = window.sessionStorage.getItem("activePath")
9.繪制用戶列表基本結(jié)構(gòu)
A.使用element-ui面包屑組件完成頂部導(dǎo)航路徑(復(fù)制面包屑代碼坚芜,在element.js中導(dǎo)入組件Breadcrumb,BreadcrumbItem)
B.使用element-ui卡片組件完成主體表格(復(fù)制卡片組件代碼,在element.js中導(dǎo)入組件Card)斜姥,再使用element-ui輸入框完成搜索框及搜索按鈕鸿竖,
此時(shí)我們需要使用柵格布局來(lái)劃分結(jié)構(gòu)(復(fù)制卡片組件代碼,在element.js中導(dǎo)入組件Row铸敏,Col)缚忧,然后再使用el-button制作添加用戶按鈕
<div>
<h3>用戶列表組件</h3>
<!-- 面包屑導(dǎo)航 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
<el-breadcrumb-item>用戶管理</el-breadcrumb-item>
<el-breadcrumb-item>用戶列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片視圖區(qū)域 -->
<el-card>
<!-- 搜索與添加區(qū)域 -->
<el-row :gutter="20">
<el-col :span="7">
<el-input placeholder="請(qǐng)輸入內(nèi)容">
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
</el-col>
<el-col :span="4">
<el-button type="primary">添加用戶</el-button>
</el-col>
</el-row>
</el-card>
</div>
10.請(qǐng)求用戶列表數(shù)據(jù)
<script>
export default {
data() {
return {
//獲取查詢(xún)用戶信息的參數(shù)
queryInfo: {
query: '',
pagenum: 1,
pagesize: 2
},
//保存請(qǐng)求回來(lái)的用戶列表數(shù)據(jù)
userList:[],
total:0
}
},
created() {
this.getUserList()
},
methods: {
async getUserList() {
//發(fā)送請(qǐng)求獲取用戶列表數(shù)據(jù)
const { res: data } = await this.$http.get('users', {
params: this.queryInfo
})
//如果返回狀態(tài)為異常狀態(tài)則報(bào)錯(cuò)并返回
if (res.meta.status !== 200)
return this.$message.error('獲取用戶列表失敗')
//如果返回狀態(tài)正常,將請(qǐng)求的數(shù)據(jù)保存在data中
this.userList = res.data.users;
this.total = res.data.total;
}
}
}
</script>
11.將用戶列表數(shù)據(jù)展示
使用表格來(lái)展示用戶列表數(shù)據(jù)杈笔,使用element-ui表格組件完成列表展示數(shù)據(jù)(復(fù)制表格代碼闪水,在element.js中導(dǎo)入組件Table,TableColumn)
在渲染展示狀態(tài)時(shí),會(huì)使用作用域插槽獲取每一行的數(shù)據(jù)
再使用switch開(kāi)關(guān)組件展示狀態(tài)信息(復(fù)制開(kāi)關(guān)組件代碼蒙具,在element.js中導(dǎo)入組件Switch)
而渲染操作列時(shí)球榆,也是使用作用域插槽來(lái)進(jìn)行渲染的,
在操作列中包含了修改禁筏,刪除持钉,分配角色按鈕,當(dāng)我們把鼠標(biāo)放到分配角色按鈕上時(shí)
希望能有一些文字提示篱昔,此時(shí)我們需要使用文字提示組件(復(fù)制文字提示組件代碼每强,在element.js中導(dǎo)入組件Tooltip),將分配角色按鈕包含
代碼結(jié)構(gòu)如下:
<!-- 用戶列表(表格)區(qū)域 -->
<el-table :data="userList" border stripe>
<el-table-column type="index"></el-table-column>
<el-table-column label="姓名" prop="username"></el-table-column>
<el-table-column label="郵箱" prop="email"></el-table-column>
<el-table-column label="電話" prop="mobile"></el-table-column>
<el-table-column label="角色" prop="role_name"></el-table-column>
<el-table-column label="狀態(tài)">
<template slot-scope="scope">
<el-switch v-model="scope.row.mg_state"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="180px">
<template slot-scope="scope">
<!-- 修改 -->
<el-button type="primary" icon="el-icon-edit" size='mini'></el-button>
<!-- 刪除 -->
<el-button type="danger" icon="el-icon-delete" size='mini'></el-button>
<!-- 分配角色 -->
<el-tooltip class="item" effect="dark" content="分配角色" placement="top" :enterable="false">
<el-button type="warning" icon="el-icon-setting" size='mini'></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
12.實(shí)現(xiàn)用戶列表分頁(yè)
A.使用表格來(lái)展示用戶列表數(shù)據(jù),可以使用分頁(yè)組件完成列表分頁(yè)展示數(shù)據(jù)(復(fù)制分頁(yè)組件代碼州刽,在element.js中導(dǎo)入組件Pagination)
B.更改組件中的綁定數(shù)據(jù)
<!-- 分頁(yè)導(dǎo)航區(qū)域
@size-change(pagesize改變時(shí)觸發(fā))
@current-change(頁(yè)碼發(fā)生改變時(shí)觸發(fā))
:current-page(設(shè)置當(dāng)前頁(yè)碼)
:page-size(設(shè)置每頁(yè)的數(shù)據(jù)條數(shù))
:total(設(shè)置總頁(yè)數(shù)) -->
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[1, 2, 5, 10]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
C.添加兩個(gè)事件的事件處理函數(shù)@size-change空执,@current-change
handleSizeChange(newSize) {
//pagesize改變時(shí)觸發(fā),當(dāng)pagesize發(fā)生改變的時(shí)候穗椅,我們應(yīng)該
//以最新的pagesize來(lái)請(qǐng)求數(shù)據(jù)并展示數(shù)據(jù)
// console.log(newSize)
this.queryInfo.pagesize = newSize;
//重新按照pagesize發(fā)送請(qǐng)求辨绊,請(qǐng)求最新的數(shù)據(jù)
this.getUserList();
},
handleCurrentChange( current ) {
//頁(yè)碼發(fā)生改變時(shí)觸發(fā)當(dāng)current發(fā)生改變的時(shí)候,我們應(yīng)該
//以最新的current頁(yè)碼來(lái)請(qǐng)求數(shù)據(jù)并展示數(shù)據(jù)
// console.log(current)
this.queryInfo.pagenum = current;
//重新按照pagenum發(fā)送請(qǐng)求房待,請(qǐng)求最新的數(shù)據(jù)
this.getUserList();
}
13.實(shí)現(xiàn)更新用戶狀態(tài)
當(dāng)用戶點(diǎn)擊列表中的switch組件時(shí)邢羔,用戶的狀態(tài)應(yīng)該跟隨發(fā)生改變。
A.首先監(jiān)聽(tīng)用戶點(diǎn)擊switch組件的事件桑孩,并將作用域插槽的數(shù)據(jù)當(dāng)做事件參數(shù)進(jìn)行傳遞
<el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)"></el-switch>
B.在事件中發(fā)送請(qǐng)求完成狀態(tài)的更改
async userStateChanged(row) {
//發(fā)送請(qǐng)求進(jìn)行狀態(tài)修改
const { data: res } = await this.$http.put(
`users/${row.id}/state/${row.mg_state}`
)
//如果返回狀態(tài)為異常狀態(tài)則報(bào)錯(cuò)并返回
if (res.meta.status !== 200) {
row.mg_state = !row.mg_state
return this.$message.error('修改狀態(tài)失敗')
}
this.$message.success('更新?tīng)顟B(tài)成功')
},
14.實(shí)現(xiàn)搜索功能
添加數(shù)據(jù)綁定拜鹤,添加搜索按鈕的點(diǎn)擊事件(當(dāng)用戶點(diǎn)擊搜索按鈕的時(shí)候,調(diào)用getUserList方法根據(jù)文本框內(nèi)容重新請(qǐng)求用戶列表數(shù)據(jù))
當(dāng)我們?cè)谳斎肟蛑休斎雰?nèi)容并點(diǎn)擊搜索之后流椒,會(huì)按照搜索關(guān)鍵字搜索敏簿,我們希望能夠提供一個(gè)X刪除搜索關(guān)鍵字并重新獲取所有的用戶列表數(shù)據(jù),只需要給文本框添加clearable屬性并添加clear事件,在clear事件中重新請(qǐng)求數(shù)據(jù)即可
<el-col :span="7">
<el-input placeholder="請(qǐng)輸入內(nèi)容" v-model="queryInfo.query" clearable @clear="getUserList">
<el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
</el-input>
</el-col>
15.實(shí)現(xiàn)添加用戶
A.當(dāng)我們點(diǎn)擊添加用戶按鈕的時(shí)候惯裕,彈出一個(gè)對(duì)話框來(lái)實(shí)現(xiàn)添加用戶的功能温数,首先我們需要復(fù)制對(duì)話框組件的代碼并在element.js文件中引入Dialog組件
B.接下來(lái)我們要為“添加用戶”按鈕添加點(diǎn)擊事件,在事件中將addDialogVisible設(shè)置為true蜻势,即顯示對(duì)話框
C.更改Dialog組件中的內(nèi)容
<!-- 對(duì)話框組件 :visible.sync(設(shè)置是否顯示對(duì)話框) width(設(shè)置對(duì)話框的寬度)
:before-close(在對(duì)話框關(guān)閉前觸發(fā)的事件) -->
<el-dialog title="添加用戶" :visible.sync="addDialogVisible" width="50%">
<!-- 對(duì)話框主體區(qū)域 -->
<el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px">
<el-form-item label="用戶名" prop="username">
<el-input v-model="addForm.username"></el-input>
</el-form-item>
<el-form-item label="密碼" prop="password">
<el-input v-model="addForm.password"></el-input>
</el-form-item>
<el-form-item label="郵箱" prop="email">
<el-input v-model="addForm.email"></el-input>
</el-form-item>
<el-form-item label="電話" prop="mobile">
<el-input v-model="addForm.mobile"></el-input>
</el-form-item>
</el-form>
<!-- 對(duì)話框底部區(qū)域 -->
<span slot="footer" class="dialog-footer">
<el-button @click="addDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="addDialogVisible = false">確 定</el-button>
</span>
</el-dialog>
D.添加數(shù)據(jù)綁定和校驗(yàn)規(guī)則:
data() {
//驗(yàn)證郵箱的規(guī)則
var checkEmail = (rule, value, cb) => {
const regEmail = /^\w+@\w+(\.\w+)+$/
if (regEmail.test(value)) {
return cb()
}
//返回一個(gè)錯(cuò)誤提示
cb(new Error('請(qǐng)輸入合法的郵箱'))
}
//驗(yàn)證手機(jī)號(hào)碼的規(guī)則
var checkMobile = (rule, value, cb) => {
const regMobile = /^1[34578]\d{9}$/
if (regMobile.test(value)) {
return cb()
}
//返回一個(gè)錯(cuò)誤提示
cb(new Error('請(qǐng)輸入合法的手機(jī)號(hào)碼'))
}
return {
//獲取查詢(xún)用戶信息的參數(shù)
queryInfo: {
// 查詢(xún)的條件
query: '',
// 當(dāng)前的頁(yè)數(shù)撑刺,即頁(yè)碼
pagenum: 1,
// 每頁(yè)顯示的數(shù)據(jù)條數(shù)
pagesize: 2
},
//保存請(qǐng)求回來(lái)的用戶列表數(shù)據(jù)
userList: [],
total: 0,
//是否顯示添加用戶彈出窗
addDialogVisible: false,
// 添加用戶的表單數(shù)據(jù)
addForm: {
username: '',
password: '',
email: '',
mobile: ''
},
// 添加表單的驗(yàn)證規(guī)則對(duì)象
addFormRules: {
username: [
{ required: true, message: '請(qǐng)輸入用戶名稱(chēng)', trigger: 'blur' },
{
min: 3,
max: 10,
message: '用戶名在3~10個(gè)字符之間',
trigger: 'blur'
}
],
password: [
{ required: true, message: '請(qǐng)輸入密碼', trigger: 'blur' },
{
min: 6,
max: 15,
message: '用戶名在6~15個(gè)字符之間',
trigger: 'blur'
}
],
email: [
{ required: true, message: '請(qǐng)輸入郵箱', trigger: 'blur' },
{ validator:checkEmail, message: '郵箱格式不正確,請(qǐng)重新輸入', trigger: 'blur'}
],
mobile: [
{ required: true, message: '請(qǐng)輸入手機(jī)號(hào)碼', trigger: 'blur' },
{ validator:checkMobile, message: '手機(jī)號(hào)碼不正確握玛,請(qǐng)重新輸入', trigger: 'blur'}
]
}
}
}
E.當(dāng)關(guān)閉對(duì)話框時(shí)够傍,重置表單
給el-dialog添加@close事件,在事件中添加重置表單的代碼
methods:{
....
addDialogClosed(){
//對(duì)話框關(guān)閉之后挠铲,重置表達(dá)
this.$refs.addFormRef.resetFields();
}
}
F.點(diǎn)擊對(duì)話框中的確定按鈕冕屯,發(fā)送請(qǐng)求完成添加用戶的操作
首先給確定按鈕添加點(diǎn)擊事件,在點(diǎn)擊事件中完成業(yè)務(wù)邏輯代碼
methods:{
....
addUser(){
//點(diǎn)擊確定按鈕拂苹,添加新用戶
//調(diào)用validate進(jìn)行表單驗(yàn)證
this.$refs.addFormRef.validate( async valid => {
if(!valid) return this.$message.error("請(qǐng)?zhí)顚?xiě)完整用戶信息");
//發(fā)送請(qǐng)求完成添加用戶的操作
const {data:res} = await this.$http.post("users",this.addForm)
//判斷如果添加失敗安聘,就做提示
if (res.meta.status !== 200)
return this.$message.error('添加用戶失敗')
//添加成功的提示
this.$message.success("添加用戶成功")
//關(guān)閉對(duì)話框
this.addDialogVisible = false
//重新請(qǐng)求最新的數(shù)據(jù)
this.getUserList()
})
}
}