Vue全家桶+ElementUI+Mock.Js實現的后台管理系統:學習筆記


 

-----寫在前面-----

雖然自己寫了個仿站,但小林心里十分有數,這個玩意到時候可能都不好意思寫到簡歷上,果然前端越往后面學越覺得自己之前是弟弟。

現在在看6月份的簡歷,突然明白為啥公司們都不要我...就干兩個月,技術還沒多好,打擾了(;′⌒`)

把ElementUI的官網文檔過了一遍,感嘆作者也太🐮了...大神們造的輪子屬實給勁

正好看到了一個用標題所列的技術棧搭建的一個后台管理系統,clone下來看了一下發現屬實有點腦殼疼,不過問題不大,一天看懂一些,總歸是能吃的透透的嗷

 Vue-Admin-Demo

-----2019.08.24(Day 1):目錄梳理、路由配置詳解、login.vue-----

和直接使用vue-cli以webpack模板生成的工程文件不同

作者把路由組件放在views文件夾下

api文件夾用於接收mock文件夾模擬出的數據並作為axios的請求地址(這個后面會詳解)

路由配置文件:

//省略路由的引入
 let routes = [ { path: '/login', component: Login, name: '', hidden: true }, { path: '/404', component: NotFound, name: '', hidden: true }, //{ path: '/main', component: Main },
 { path: '/', component: Home, name: '', iconCls: 'el-icon-menu', leaf: true, //只有一個節點
    children: [{ path: '/Index', component: Index, name: '首頁' }] }, { path: '/', component: Home, name: '', iconCls: 'el-icon-menu', //圖標樣式class
    leaf: true, //只有一個節點
 children: [ { path: '/Application', component: Application, name: '應用管理' } ] }, { path: '/', component: Home, name: '日志管理', iconCls: 'el-icon-menu', children: [ { path: '/SysLog', component: SysLog, name: '系統日志' }, { path: '/AdminLog', component: AdminLog, name: '管理員操作日志' }, { path: '/UserLog', component: UserLog, name: '用戶使用日志' } ] }, { path: '/', component: Home, name: '配置管理', iconCls: 'el-icon-menu', children: [ { path: '/GuidePageConfig', component: GuidePageConfig, name: '引導頁配置' }, { path: '/IntegralConfig', component: IntegralConfig, name: '積分規則配置' }, { path: '/SubscribeConfig', component: SubscribeConfig, name: '訂閱欄目配置' } ] }, { path: '/', component: Home, name: '權限管理', iconCls: 'el-icon-menu', children: [ { path: '/page4', component: Page4, name: '權限組管理' }, { path: '/Main', component: Main, name: '權限組權限管理' }, { path: '/Form', component: Form, name: '權限組人員管理' } ] }, { path: '/', component: Home, name: '賬號管理', iconCls: 'el-icon-menu', children: [ { path: '/user', component: user, name: '頁面4' }, { path: '/page5', component: Page5, name: '頁面5' } ] }, { path: '*', hidden: true, redirect: { path: '/404' } } ] export default routes
Routes.js

/login:登陸界面

/404:無效界面

 

/:通過指定不同的name屬性以及不同的嵌套組件來執行不同的跳轉(至子頁面)

這樣寫的好處是url不會是/page1/page1-1/page1-1-1,而是直接將最后一級路由拼上去。即/page1-1-1

 

iconCls: ElementUI為路由指定圖標的方式

 

hidden&leaf屬性:自定義屬性,用於后面配合指定路由是否渲染

 

login.vue

<el-form :model="ruleForm2" :rules="rules2" ref="ruleForm2" label-position="left" label-width="0px" class="demo-ruleForm login-container"
  >
    <h3 class="title">系統登錄</h3>
    <el-form-item prop="account">
      <el-input type="text" v-model="ruleForm2.account" auto-complete="off" placeholder="賬號"></el-input>
    </el-form-item>
    <el-form-item prop="checkPass">
      <el-input type="password" v-model="ruleForm2.checkPass" auto-complete="off" placeholder="密碼"></el-input>
    </el-form-item>
    <el-checkbox v-model="checked" checked class="remember">記住密碼</el-checkbox>
    <el-form-item style="width:100%;">
      <el-button type="primary" style="width:100%;" @click.native.prevent="handleSubmit2" :loading="logining"
      >登錄</el-button>
      <!--<el-button @click.native.prevent="handleReset2">重置</el-button>-->
    </el-form-item>
  </el-form>
login.vue

 

 

model:表單的數據對象,使用方式:

 

rules:驗證規則

 

label-position、label-width:表單域標簽的位置、表單域標簽的寬度

詳見 ElementUI-表單

 

 登錄按鈕:使用native修飾符,否則無法監聽到原生click事件(被封裝過的),再阻止默認事件提交,並調用handleSubmit2()事件:

 

 

-----2019-08-26 Home.Vue、Index.Vue------

 

 <el-dropdown>

 

 trigger:觸發菜單展開的行為

divided:顯示分割線

更多下拉菜單相關

 

<el-breadcrumb>面包屑導航

在這里是利用跟蹤路由變化來進行渲染新的面包屑導航項,例如進入一個二級路由界面后,$route.matched會被推入新的項,此時面包屑導航會多渲染出新的一項

 

 菜單
<aside>-<el-menu>-<el-submenu>

菜單也是通過v-for渲染的,不渲染hidden為true的路由項(login.vue、404.vue等),為leaf屬性為true的一級菜單路由渲染其子路由

同時通過前面為路由自定義的iconCls屬性來添加菜單圖標

 注意有兩個圖標

 

 

 

Index.Vue

沒啥好分析的,就是這里的echarts到時候需要看看文檔

 

 

-----2019.08.27 Mock邏輯(獲取用戶列表、登陸驗證邏輯) -----

獲取用戶列表的MOCK邏輯見這篇博文:Vue & Axios & Mock & Axios-Mock-Adapter:在Vue項目中模擬接口、請求以及數據

登陸驗證邏輯

api.js

export const requestLogin = params => { return axios.post(`${base}/login`, params).then(res => res.data); };

 

login.vue 中點擊登錄按鈕后的處理邏輯

handleSubmit2(ev) { var _this = this
      this.$refs.ruleForm2.validate(valid => { if (valid) { this.logining = true
          var loginParams = { username: this.ruleForm2.account, password: this.ruleForm2.checkPass }//即傳過去的參數包含填入的帳號與密碼
          requestLogin(loginParams).then(data => { console.log(data);//{code: 200, msg: "請求成功", user: {…}}
            this.logining = false
            //NProgress.done();
            let { msg, code, user } = data if (code !== 200) { this.$message({ message: msg, type: 'error' }) } else { sessionStorage.setItem('user', JSON.stringify(user)) this.$router.push({ path: '/Index' }) } }) } else { console.log('error submit!!') return false } }) }

 

Mock.js中的登陸相關邏輯

mock.onPost('/login').reply(config => { let { username, password } = JSON.parse(config.data); //解構賦值
      return new Promise((resolve, reject) => { let user = null; setTimeout(() => { let hasUser = LoginUsers.some(u => { //LoginUsers是寫死的嗷
            //some方法檢測數組中的元素是否符合指定條件,如果有一個滿足就會返回true
            if (u.username === username && u.password === password) { user = JSON.parse(JSON.stringify(u)); user.password = undefined; return true; } }); //如果驗證通過
          if (hasUser) { resolve([200, { code: 200, msg: '請求成功', user }]); //調用resolve方法,Promise變為操作成功狀態(fulfilled),執行then方法里面onfulfilled里的操作
            //Promise.resolve方法會將這個對象轉為 Promise 對象,然后就立即執行thenable對象的then方法。
          } else { resolve([200, { code: 500, msg: '賬號或密碼錯誤' }]); } }, 1000); }); });

 

大概的思路是這樣的:

(login.vue)點擊按鈕后將調用requestLogin()方法,賬號密碼以POST方式發送至代理的接口地址('/login')

(mock.js)mock攔截到請求,在onPost()方法中進行驗證,並根據驗證結果調用resolve()方法(傳入的參數不同),reply()中返回的這個Promise對象狀態變為成功(fulfilled)

隨后會調用login.vue中、定義在requestLogin()方法后的then()方法,解構賦值后根據code值判斷驗證的成功還是失敗

 

 

-----2019-08-28:查詢、新增、編輯、刪除操作、slot-scope&slot-----

⚠slot-scope是被廢棄的API(現在建議使用v-slot),但由於原作者在完成這個項目時使用的是2.2.2版本的Vue,正好這個用法我之前也沒學過就順便了解一下。

官方文檔地址:slot-scope  v-slot

注意這個表格的代碼,借助ElementUI的幫助,可以直接在data屬性注入數據,然后在<el-table-column>中通過為prop設定對應鍵名來填充數據。

表格里的template就是每一行都相同的【編輯】、【刪除】按鈕,如何在點擊時直到是哪一行(的哪一項)需要進行操作?就是靠slot-scope

我們這里把scope整個打印出來看看

$idnex:0  這里點擊的是第一行的數據

column:該按鈕的列屬性,即第?列

row:

行屬性,包括行頭與單元格值

store:表格內部的狀態管理,這里略過

ElementUI官網的demo:Table-ElementUI

 

接下來是各個操作的詳解:

刪除:

關於this.$confirm:

具體參見MessageBox彈框 

 

Mock.js中負責刪除邏輯的部分:

實際上就是把數據用fliter()方法走了一遍,並修改了全局的_Users變量--->然后再次調用getUser()方法--->用新的_Users渲染列表

⬆這個邏輯可以看前兩天的分析

 

編輯:這個復雜一些

首先是顯示編輯界面,並且將這一行數據的所有屬性復制一份保存下來

Object.assign()方法(MDN)

 

注意這里的 :visible.sync="editFormVisible",建議去學一下.sync的用法,這里指稍微提一下

這個寫法表達了對visible賦新值的意圖,跳過了使用$emit通知組件去修改的過程(ElementUI的組件都是被封裝過的哈記得)

 

提交編輯的邏輯函數:

在Mock.js中的功能函數:(邏輯就不用多說了吧)

新增的邏輯實現類似編輯,最后來看一哈 批量刪除 這個功能

 

首先列表項前的單選框被勾選會觸發selesChange()方法(見下行使用方式)
<el-table :data="users" highlight-current-row v-loading="listLoading" @selection-change="selsChange" style="width: 100%;">

 

注意!這里的sels是所有當前被選中的項!

創建一個ids數組,並將被選中的項的id填入進去,並化為字符串形式,發送給mock.js中的batchRemoveUser()進行處理

 

 

-----2019-08-31 積分配置   訂閱欄目配置-----

喵喵喵??我發現這個作者后面幾個子頁面就是在偷懶了... 所有子界面有意義的就只有用戶列表和積分配置頁面,

其他不是復制的用戶列表就是無意義字符...但這個項目我還是學到了很有分量的東西的。

把積分配置界面魔改了一下

 

 

 現在保存配置后會把積分的配置規則發到服務器端(模擬的)~

改動如下:

1.

 

 

 這樣會把新的積分配置作為一個數組直接發送出去~

 

在api.js中新增一個接口:

export const IntegralConfig = params => { return axios.post(`${base}/user/IntegralConfig`, { params: params }) }

在mock.js中修改代理配置:

mock.onPost('/user/IntegralConfig').reply(config => { console.log(JSON.parse(config.data).params.nums); var [step1, step2, step3, step4] = JSON.parse(config.data).params.nums; console.log(step1, step2, step3, step4); return new Promise((resolve, reject) => { setTimeout(() => { resolve([ 200, { code: 200, msg: '積分規則變更成功' } ]); }, 500); }); });

 

引導頁、宣傳頁配置(這兩個模式是一樣的,就以宣傳頁配置為例)

 

<h1>宣傳頁配置 <el-switch style="display: block" v-model="GuidePageConfig" active-color="#13ce66" inactive-color="#ff4949" active-text="打開宣傳頁" inactive-text="關閉宣傳頁">
            </el-switch>
            </h1>
        </el-col>
        <el-col>

        </el-col>
        <el-form>
            <el-upload action="https://jsonplaceholder.typicode.com/posts/" list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :file-list="fileList2">
                <i class="el-icon-plus"></i>
            </el-upload>
            <el-dialog :visible.sync="dialogVisible">
                <img width="100%" :src="dialogImageUrl" alt="">
            </el-dialog>

關於el-upload的使用參見官網:el-upload

 

 

 

 

action:上傳到的服務器地址

list-type:文件列表類型

on-preview:點擊文件列表中已上傳的文件時的鈎子

 

 

 

 在這里會使得對話框可見並展示大尺寸的圖片

on-remove:文件列表移除文件時的鈎子

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM