1. 安裝 vue-cli & 創建項目
# 安裝 vue-cli 因爲是全局安裝,安裝過一次之後再創建項目就不用安裝了;
> npm i -g @vue/cli
# 創建項目
> vue create vue-web
# 進入項目目錄
> cd vue-web
# 啓動項目
> npm run serve
# 訪問:
http://localhost:8080/
2. 安裝 iview
安裝 iview
> npm i iview
引入 iview main.js
import Vue from 'vue'
import iview from 'iview'
import 'iview/dist/styles/iview.css'
Vue.use(iview)
3. 安裝 less
# less-loader
> npm i less-loader
# less
> npm i less -D
4. 安裝並配置路由 vue-router
安裝 vue-router
npm i vue-router
引入 & 配置 vue-router
import Vue from 'vue'
import vueRouter from 'vue-router'
// 安裝 vue-router 插件
Vue.use(vueRouter);
// vue-router 實例化對象
const router = new vueRouter({
mode: 'history',
routes: []
})
// 暴露出去
export default router;
vue-router 官網
5. 使用路由
創建頁面:
登錄(Login.vue
) ,後臺(Admin.vue
),
後臺-歡迎頁面(admin/Welcome.vue
),後臺-用戶管理(admin/User.vue
)等
導入路由:main.js
import router from './router/index'
new Vue({
render: h => h(App),
router
}).$mount('#app')
路由出口
main.js
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
配置路由
// vue-router 實例化對象
const router = new vueRouter({
mode: 'history',
routes: [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
component: () => import('../pages/Login.vue')
},
{
path: '/sys',
component: () => import('../pages/Admin.vue'),
children: [
{
path: '',
component: ()=> import('../pages/admin/Welcome.vue')
},
{
path: 'user',
component: () => import('../pages/admin/User.vue')
}
]
},
{
path: '/404',
component: () => import('../pages/notFind.vue')
},
{
path: '*',
redirect: '/404'
}
]
})
子路由出口 pages/Admin.vue
<div>
admin
<router-view></router-view>
</div>
6. 使用 iview 搭建頁面
- 登錄頁面
- 後臺框架
- 後臺歡迎頁面
7. 登錄 & 菜單列表
詳細的登錄流程見如下博客:
管理員部分
頁面大體如下:
8. 請求管理員數據
新建接口 /api/getUserInfo.js
* 注意:GET 請求的參數是一個對象,通過這個對象的 params屬性傳遞的!!
/**
* 管理員列表
*/
import http from './http'
function getUserInfo(data) {
return http.get('/sys/user/list', {
params: data
})
}
export default getUserInfo;
在 User.vue
頁面請求數據 beforeCreate()
將要用的數據在 data
選項中定義好,然後將請求到的數據存儲起來
import getUserInfo from '../../api/getUserInfo'
data(){
return {
// 表體數據
userList: [],
// 當前頁碼
currPage: 1,
// 每頁條數
pageSize: 10,
// 總條數
totalCount: 1,
// 總頁數
totalPage: 1
}
},
beforeCreate() {
getUserInfo({
page: 1,
limit: 1,
sidx: 'username',
order: 'desc',
username: ''
}).then((res)=>{
const {code, msg, page} = res.data;
if(code === 0){
const {currPage, list, pageSize, totalCount, totalPage} = page;
// 將請求到的數據存儲起來
this.currPage = currPage;
this.userList = list;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.totalPage = totalPage;
}else{
this.$Message.error(msg)
}
})
}
9. Table 表部分
iview中的 Table
組件循環是提供一個表頭數組,提供一個表體數組;
表體數組我們已經得到了,根據表體數據寫一個表頭數組循環生成 Table
表
data(){
return {
// 表頭
userHeader: [
/**
* 表格前邊的複選框 type: 'selection',
* 還可以設置每一列的寬度,這一列是否固定在左側或者右側等屬性
*/
{
type: 'selection',
width: 50
},
{
title: '#',
key: 'userId'
},
{
title: '用戶名',
key: 'username'
},
{
title: '郵箱',
key: 'email'
},
{
title: '手機號碼',
key: 'mobile'
},
{
title: '創建時間',
key: 'createTime'
}
]
}
}
<Table :columns="userHeader" :data="userList"></Table>
因爲我們請求到的數據並沒有操作按鈕部分,所以需要我們使用 Table
組件的 render
函數生成操作按鈕;
就在表頭數組中;
- 方法一,使用 render函數生成結構
{
title: '操作',
align: 'center',
render: (h) => h('div', [
h('Button','編輯'),
h('Button','刪除')
])
}
- 方法二,引用外部組件
創建組件 components/UserTools.vue
<template>
<div>
<Button> 編輯 </Button>
<Button> 刪除 </Button>
</div>
</template>
導入組件(局部組件,不過在 render函數中,局部組件和全局組件都可以使用)
import UserTools from '../../components/UserTools.vue'
在表頭數組中,通過render 函數使用導入的組件
{
title: '操作',
align: 'center',
render: (h) => h(UserTools)
}
觸發事件:在組件內部觸發,render函數中處理
<Button @click="$emit('edit')"> 編輯 </Button>
<Button @click="$emit('del')"> 刪除 </Button>
{
title: '操作',
align: 'center',
render: (h) => h(UserTools, {
// 使用箭頭函數,使用普通函數的話獲取不到 this指向
on: {
edit: ()=> {
console.log('編輯')
},
del: ()=> {
console.log('刪除');
}
}
})
}
但是新的問題又來了,我們怎麼知道是點擊的哪一行的操作按鈕呢?
通過 render函數中的第二個參數(params
),可以知道點擊的是哪一行的按鈕
{
title: '操作',
align: 'center',
render: (h, params) => h(UserTools, {
on: {
edit: ()=> {
console.log('編輯', params)
},
del: ()=> {
console.log('刪除', params);
}
}
})
}
10. 搜索功能
- 在搜索輸入框綁定數據
<Input
search
v-model="usernameSearch"
/>
data() {
return {
usernameSearch: ''
}
}
- 將我們
data
中的數據和請求用戶信息的時候傳入的數據綁定在一起
這樣我們操控 data
中的數據之後,再次請求到的就是我們想要的數據了
data() {
return {
// 表頭數據
userHeader: [ ... ],
// 表體數據
userList: [],
// 當前頁碼
currPage: 1,
// 每頁條數
pageSize: 10,
// 總條數
totalCount: 1,
// 總頁數
totalPage: 1,
// 搜索框的輸入
usernameSearch: ''
}
}
beforeCreate(){
// 解構 this,簡化下方操作
const {currPage, pageSize, usernameSearch} = this;
// 請求的參數,綁定 data中的數據
getUserInfo({
page: currPage,
limit: pageSize,
sidx: 'username',
order: 'desc',
username: usernameSearch
}).then((res)=>{
const {code, msg, page} = res.data;
if(code === 0){
const {currPage, list, pageSize, totalCount, totalPage} = page;
// 將請求返回的數據,和 data中的數據再次綁定
this.currPage = currPage;
this.userList = list;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.totalPage = totalPage;
}else{
this.$Message.error(msg)
}
})
}
- 不管是 搜索 還是 分頁,都是我們改變
data
中的數據,然後再次執行getUserInfo()
函數,請求新的數據;
我們之前是在 beforeCreate()
鉤子中請求初始數據,因爲需要在不少地方調用請求數據的方法,就不能在 beforeCreate()
中直接請求了,要封裝成一個方法;
下面我們就創建一個方法(getUserInfoList()
),用來請求數據;
在 created()
鉤子中調用一下請求數據的方法,用來初始化,因爲 beforeCreate()
鉤子中得不到這個方法
created(){
this.getUserInfoList();
},
methods: {
getUserInfoList(){
const {currPage, pageSize, usernameSearch} = this;
getUserInfo({
page: currPage,
limit: pageSize,
sidx: 'username',
order: 'desc',
username: usernameSearch
}).then((res)=>{
const {code, msg, page} = res.data;
if(code === 0){
const {currPage, list, pageSize, totalCount, totalPage} = page;
this.currPage = currPage;
this.userList = list;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.totalPage = totalPage;
}else{
this.$Message.error(msg)
}
})
}
}
- 自動搜索,輸入後直接進行搜索
直接監聽搜索框綁定的數據usernameSearch
的變化,如果變化就再次請求數據就好了
watch: {
usernameSearch() {
this.getUserInfoList();
}
}
- 手動搜索,可以解決多人同時搜索的時候併發量太大的問題
通過 <Input>
控件的 on-search
事件解決;
事件名 | 說明 | 返回值 |
---|---|---|
on-search | 開啓 search 時可用,點擊搜索或按下回車鍵時觸發 | value |
將 <Input >
中的 v-model="usernameSearch"
去掉;添加上 @on-search
事件
<Input
search
@on-search="handleSearch"
/>
data() {
return {
// 搜索框的輸入
usernameSearch: '',
}
},
methods: {
/**
* 搜索
* value 搜索框中的內容
*/
handleSearch(value){
this.usernameSearch = value
}
},
watch: {
usernameSearch() {
// 請求數據
this.getUserInfoList();
},
}
- 分頁也是如此,直接監聽當前頁碼
currPage
這個數據的變化就好了
watch: {
currPage() {
this.getUserInfoList();
}
}
- 給表格的數據切換添加 loading…
給 Table
控件添加 loading
屬性,並綁定數據
<Table
:columns="userHeader"
:data="userList"
:loading="tableLoading"
></Table>
data() {
return {
// 表格加載狀態
tableLoading: false
}
}
在請求數據的時候,將 tableLoading
變成 true
,請求完成之後,不管是請求成功還是請求失敗,都把 tableLoading
變成 false
11. 分頁功能
- 改變分頁,直接監聽當前頁碼
currPage
這個數據的變化,如果有改變請求一次數據就好了
watch: {
currPage() {
this.getUserInfoList();
}
}
- 每頁展示條數的控制
<!--
total: 總條數
current: 當前頁碼,支持 .sync 修飾符
page-size: 每頁條數
page-size-opts: Array 條數控制選項
@on-page-size-change: 切換每頁條數時的回調,返回切換後的每頁條數
-->
<Page
show-sizer
:total="totalCount"
:current.sync="currPage"
:page-size="pageSize"
:page-size-opts="[1, 5, 10, 20]"
@on-page-size-change="pageSizeChange"
/>
methods: {
/**
* 每頁條數改變
* num 當前選中的條數
*/
pageSizeChange(num){
this.pageSize = num;
}
}
watch: {
// 當頁碼發生改變的時候,重新請求數據
pageSize() {
this.getUserInfoList();
}
}
12. 添加 & 編輯管理員
- 搭建佈局
使用模態框組件<Modal>
搭建如下佈局
其中開關組件<Switch>
需要注意: 直接使用是不會顯示的,需要加上前綴 <i-Switch>
開關這裏,因爲我們後臺需要的不是 true false
而是 1 0
,所以通過 true-value false-value
屬性設置;
<Modal v-model="modalShow" :title="modalTitle" >
<Form
:label-width="40"
label-position="left"
>
<FormItem label="賬號" >
<Input prefix="md-person" placeholder="username" />
</FormItem>
<FormItem label="密碼" >
<Input prefix="md-lock" type="password" placeholder="password" />
</FormItem>
<FormItem label="郵箱" >
<Input prefix="md-mail" placeholder="email" />
</FormItem>
<FormItem label="手機" >
<Input prefix="md-phone-portrait" placeholder="mobile" />
</FormItem>
<FormItem label="狀態" >
<i-Switch
size="large"
:true-value="1"
:false-value="0"
>
<span slot="open">激活</span>
<span slot="close">禁用</span>
</i-Switch>
</FormItem>
</Form>
</Modal>
data() {
return {
modalShow: true,
modalTitle: '添加管理員'
}
}
- 綁定數據
<Form :model="modalForm" >
<FormItem>
<Input v-model="modalForm.username" />
</FormItem>
<!--
...
-->
</Form>
data() {
return {
// 模態框表單
modalForm: {
userId: 0,
username: '',
password: '',
email: '',
mobile: '',
status: 0,
roleIdList: []
},
}
}
- 表單數據驗證
iview表單驗證:https://blog.csdn.net/qq_39125684/article/details/91125528
# 安裝validator 庫,方便自定義驗證
> npm i validator
// 導入
import validator from 'validator'
<Form :rules="modalRules" >
<FormItem
label="賬號"
prop="username"
>
<Input v-model="modalForm.username" />
</FormItem>
</Form>
data() {
return {
// 模態框 表單驗證
modalRules: {
username: [
{required: true, message: '用戶名不能爲空'}
],
email: [
{required: true, message: '郵箱不能爲空'},
{validator: (rule, value, callback)=>{
if(validator.isEmail(value)){
callback()
}else{
callback(new Error('郵箱格式不正確'))
}
}}
],
mobile: [
{required: true, message: '手機號碼不能爲空'},
{validator: (rule, value, callback)=>{
if(validator.isMobilePhone(value, 'zh-CN')) {
callback()
}else{
callback(new Error('手機號碼格式不正確'))
}
}}
]
}
}
}
- 添加管理員按鈕 & 編輯管理員
<Button @click="modalTitle='添加管理員',modalShow=true">添加管理員</Button>
{
title: '操作',
align: 'center',
render: (h, params) => h(UserTools, {
on: {
edit: ()=> {
this.modalShow = true;
this.modalTitle = "編輯管理員"
},
del: ()=> {
console.log('刪除', params);
}
}
})
}
- 編輯管理員,模態框的表單中要有當前行的數據
{
title: '操作',
align: 'center',
render: (h, params) => h(UserTools, {
on: {
edit: ()=> {
this.modalShow = true;
this.modalTitle = "編輯管理員";
// 獲取到當前行的數據,賦值給模態框表單
const {userId, email, mobile, username, password, status, roleIdList} = params.row;
this.modalForm = {
userId,
username,
password: '',
email,
mobile,
status,
roleIdList,
}
},
del: ()=> {
console.log('刪除', params);
}
}
})
}
- 但是由此帶來新的問題
當我們點擊完編輯某個用戶的信息之後,再點擊添加,則添加對話框中會有剛纔用戶的信息
所以我們要知道模態框是什麼時候關閉的,在關閉的時候,我們把模態框表單中的內容清空就好了;
Modal
事件
事件名 | 說明 | 返回值 |
---|---|---|
on-ok | 點擊確定的回調 | 無 |
on-cancel | 點擊取消的回調 | 無 |
Form
方法
方法名 | 說明 | 參數 |
---|---|---|
resetFields | 對整個表單進行重置,將所有字段值重置爲空並移除校驗結果 | 無 |
iview
提供瞭如上事件和方法,做起來就很簡單了
首先 給 <Modal>
對話框的關閉按鈕添加事件
<Modal
@on-cancel="modalCancel"
>
然後 給將要清空的 <Form>
表單添加 ref
,方便後面可以通過 this.$refs
找到
<Form
ref="modalForm"
>
最後 在modalCancel
函數中找到 <Form>
,執行一下 resetFields()
,清空掉就好了
methods: {
/**
* 模態框點擊取消時 執行
*/
modalCancel(){
this.$refs['modalForm'].resetFields();
},
}
- 添加 & 編輯 管理員的業務邏輯
編寫接口
addUser.js 文件
/**
* 添加管理員
*/
import http from './http'
function addUser(data){
return http.post('/sys/user/save', data)
}
export default addUser;
editUser.js 文件
/**
* 編輯管理員信息
*/
import http from './http'
function editUser(data) {
return http.post('/sys/user/update', data)
}
export default editUser;
在頁面中導入接口
import addUser from '../../api/addUser'
import editUser from '../../api/editUser'
因爲添加管理員和編輯管理員使用的是同一個表單,所以在點擊確定按鈕,提交數據的時候要做一下判斷;
<Modal
@on-ok="modalSubmit"
>
點擊確定按鈕的時候進行一下表單驗證,驗證通過則調用接口,請求數據
methods: {
/**
* 模態框點擊確定的時候執行
*/
modalSubmit(){
// 先做一下驗證
this.$refs['modalForm'].validate((result)=>{
if(result){
// 驗證通過 判斷是添加還是編輯
if(this.modalTitle == '添加管理員'){
addUser({
...this.modalForm
}).then((res)=>{
const {code, msg} = res.data;
if(code === 0){
this.$Message.success('恭喜您,數據添加成功');
this.getUserInfoList();
}else{
this.$Message.error('錯誤:'+ msg)
}
});
}else if(this.modalTitle == '編輯管理員'){
editUser({
...this.modalForm
}).then((res)=> {
const {code, msg} = res.data;
if(code === 0){
this.$Message.success('恭喜您,數據更新成功');
this.getUserInfoList();
}else{
this.$Message.error('錯誤:'+ msg)
}
})
}
}
})
}
}
13. 刪除管理員
- 定義接口
deleteUser.js
/**
* 刪除用戶
*/
import http from './http'
function deleteUser(data){
return http.post('/sys/user/delete', data)
}
export default deleteUser;
- 刪除單項
在表頭數據部分:
del: ()=> {
// 拿到當前行的用戶的 ID
const { userId } = params.row;
// 模態框詢問一下是否確定刪除
this.$Modal.confirm({
title: '刪除',
content: '<p>您確定要刪除該數據嗎?</p>',
onOk: () => {
deleteUser([userId]).then((res)=> {
if(res.data.code === 0){
this.$Message.success('刪除成功');
this.getUserInfoList();
}else{
this.$Message.error('刪除失敗:' + res.data.msg)
}
})
},
onCancel: () => {
this.$Message.info('取消刪除');
}
});
}
- 批量刪除
Table
事件
事件名 | 說明 | 返回值 |
---|---|---|
on-selection-change | 在多選模式下有效,只要選中項發生變化時就會觸發 | selection :已選項數據 |
找到選中的項
<Table
@on-selection-change="selectionChange"
></Table>
// 存儲將要刪除的用戶的ID
data() {
return {
selections: []
}
}
/**
* 拿到選中數據的 userId
*/
selectionChange(selection){
this.selections = selection.map((item, index, arr)=>{
return item.userId;
})
},
點擊刪除按鈕,刪除選中的數據
<Button @click="deleteSome">批量刪除</Button>
/**
* 批量刪除 按鈕點擊事件
* 注意:先判斷一下是否有選中的數據
*/
deleteSome(){
// 判斷一下是否有選中的數據
if(this.selections.length > 0){
// 模態框詢問一下是否確定刪除
this.$Modal.confirm({
title: '刪除',
content: '<p>您確定要刪除選中的數據嗎?</p>',
onOk: () => {
// 刪除
deleteUser([
...this.selections
]).then((res)=> {
if(res.data.code === 0){
this.$Message.success('刪除成功');
this.getUserInfoList();
}else{
this.$Message.error('刪除失敗:' + res.data.msg)
}
})
},
onCancel: () => {
this.$Message.info('取消刪除');
}
});
}else {
this.$Message.info('請選擇將要刪除的數據')
}
}
至此,一個 vue-cli項目的,登錄流程,增刪改查已經完成了;
積跬步,而至千里;
共勉;