后臺(tái)管理系統(tǒng)的項(xiàng)目小結(jié)

后臺(tái)管理系統(tǒng)的項(xiàng)目小結(jié)
寫(xiě)起來(lái)卻觸及到不少知識(shí)點(diǎn),關(guān)于vue全家桶什么的都用到了
實(shí)現(xiàn)功能或者一些想記錄的點(diǎn)
1.登錄(axios實(shí)例和攔截器)
2.動(dòng)態(tài)側(cè)邊欄和面包屑(this.$router.options.routes,meta路由元的使用)
3.iconfont的使用
4.頁(yè)面布局和可復(fù)用組件
5.element-ui,js-cookie,一些工具方法的使用
6.vuex模塊化和抽離api接口
7.es6/7和webpack的一些語(yǔ)法
實(shí)現(xiàn)思路
登錄:獲取用戶(hù)表單信息,提交后給后端接口驗(yàn)證,如果匹配則返回一個(gè)token,使用cookie存儲(chǔ),再根據(jù)token去拉取用戶(hù)信息接口獲取信息,這里的具體操作主要看后端接口如何書(shū)寫(xiě),登錄成功后,跳轉(zhuǎn)至主頁(yè)面。

這里使用自定義配置創(chuàng)建axios實(shí)例:axios.create([config]),指定的配置將與實(shí)例配置合并:axios#get(url [,config]),這里會(huì)配置基本路徑和超時(shí)時(shí)間。還使用了axios攔截器,這里使用request攔截器是為了在每個(gè)請(qǐng)求頭塞入token,好讓后端對(duì)請(qǐng)求進(jìn)行權(quán)限驗(yàn)證(根據(jù)業(yè)務(wù)而定),response攔截器,當(dāng)服務(wù)端返回特殊的狀態(tài)碼,做統(tǒng)一處理。

其中有一個(gè)導(dǎo)航守衛(wèi),有組件需要登錄才能展示,這個(gè)練習(xí)項(xiàng)目中,是先登錄才能展示其他頁(yè)面,不登錄無(wú)法展示頁(yè)面,所以有一個(gè)全局的導(dǎo)航守衛(wèi)。這里注冊(cè)一個(gè)全局前置守衛(wèi),當(dāng)一個(gè)導(dǎo)航觸發(fā)時(shí),全局前置守衛(wèi)按照創(chuàng)建順序調(diào)用。守衛(wèi)是異步解析執(zhí)行,此時(shí)導(dǎo)航在所有守衛(wèi) resolve 完之前一直處于 等待中。

每個(gè)守衛(wèi)方法接收三個(gè)參數(shù):

router.beforeEach((to, from, next) => {
  // ...
})
router.beforeEach((to,from,next)=>{
    if(getToken()){
        if(to.path==='/login'){
            next({path:'/'})
        }else{
            if(store.getters.roles.length===0){  //判斷當(dāng)前用戶(hù)是否已拉取完user_info信息
                store.dispatch('GetInfo').then(res=>{//拉取user_info
                    next()
                }).catch(()=>{
                    store.dispatch('FedLogOut').then(()=>{
                        Message.error('驗(yàn)證失敗,請(qǐng)重新登錄')
                        next({path:'/login'})
                    })
                })
            }else{
                next()
            }
        }
    }else{
        if(whiteList.indexOf(to.path)!==-1){
            next()
        }else{
            next('/login')

        }
    }
})

具體實(shí)現(xiàn)思路,當(dāng)用戶(hù)點(diǎn)擊提交按鈕,對(duì)表單信息格式驗(yàn)證,如果通過(guò)則觸發(fā)vuex的actions里面login方法,在回調(diào)中跳轉(zhuǎn)至主頁(yè)面。actions的login方法的主要操作是調(diào)用api接口,處理數(shù)據(jù),login里面是設(shè)置cookie('Token',token)和改變state的token,因?yàn)槭钦{(diào)用的api接口,所以在api里面的login接口,是主要書(shū)寫(xiě)接口的。

api文件的login接口

import axios from '@/utils/request'  //request中,創(chuàng)建了axios實(shí)例和攔截器的書(shū)寫(xiě)
export const login=(username, password)=>{
 return axios.post('/user/login',{username,password})
}

actions的login方法

Login({commit},userInfo){  //負(fù)責(zé)接口處理
             const username=userInfo.name.trim()
            return new Promise((resolve,reject)=>{
                login(username,userInfo.password).then(res=>{
                    const data=res.data  //接收值
                    setToken(data.token) //設(shè)置cookie
                    commit('SET_TOKEN',data.token)   //設(shè)置state的token
                    console.log(data)
                    resolve()
                }).catch(error=>{
                    reject(error)
                })
            })
        }
//添加請(qǐng)求攔截器
axios.interceptors.request.use(function(config){
     //在發(fā)送請(qǐng)求之前做某事
     return config;
   },function(error){
     //請(qǐng)求錯(cuò)誤時(shí)做些事
     return Promise.reject(error);
   });
//添加響應(yīng)攔截器
axios.interceptors.response.use(function(response){
     //對(duì)響應(yīng)數(shù)據(jù)做些事
     return response;
   },function(error){
     //請(qǐng)求錯(cuò)誤時(shí)做些事
     return Promise.reject(error);
   });

2動(dòng)態(tài)側(cè)邊欄和面包屑
根據(jù)路由里面的配置,動(dòng)態(tài)生成導(dǎo)航,router里面配置了meta,寫(xiě)了導(dǎo)航標(biāo)題和小圖標(biāo)。在導(dǎo)航組件中遍歷this.$router.options.routes ,這個(gè)可以獲取到路由的信息,遍歷時(shí)會(huì)有一些條件判斷,根據(jù)需要來(lái)遍歷,展示相應(yīng)的導(dǎo)航。
3.iconfont的使用,看了大神的代碼,原來(lái)優(yōu)雅的代碼是這樣的,這個(gè)已經(jīng)寫(xiě)過(guò)總結(jié),這里就不寫(xiě)了。
4.vuex模塊化和api接口
對(duì)于一些大型項(xiàng)目可以把vuex進(jìn)行模塊劃分,調(diào)用模塊里的方法需要帶上模塊名,而getters卻是不區(qū)分模塊的,所以getters的命名不能重復(fù)。api文件里面主要是抽離出來(lái)的api接口,最好組件名和接口文件命名相同,便于查找。
5 代理跨域proxy
在本地開(kāi)發(fā)環(huán)境中一般會(huì)在proxytable里面進(jìn)行設(shè)置,但是在生產(chǎn)環(huán)境中還是需要解決跨域的問(wèn)題,所以在config/dev.env.js和config/prod.env.js都設(shè)置一下
dev.env.js

'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  BASE_API: '"https://www.xxx.com"',
})

prod.env.js

'use strict'
module.exports = {
  NODE_ENV: '"production"',
  BASE_API: "https://www.xxx.com",
}

這里單獨(dú)寫(xiě)了一個(gè)js文件來(lái)處理請(qǐng)求

// 創(chuàng)建axios實(shí)例
const service = axios.create({
  baseURL: process.env.BASE_API, // api的base_url,是開(kāi)發(fā)環(huán)境還是生產(chǎn)環(huán)境會(huì)自動(dòng)尋找路徑
  timeout: 15000 // 請(qǐng)求超時(shí)時(shí)間
})
export default service

在main.js中引入,全局注冊(cè)

import axios from './api/index.js'
Vue.prototype.$axios=axios

使用

this.$axios.get('api/v1/topic/'+this.id)
                .then(res=>{
                    
                })

項(xiàng)目過(guò)程中的記錄

1 子組件和一些可復(fù)用組件
2 slot
3 :routes="[child]" :key="child.path"
4matched=[{path:'/dashboard',meta:{title:Dashboard}}].concat(matched)
5filter
6 有header+main+sidebar,怎么在 main中點(diǎn)擊 Header組件里的menu,去觸發(fā) SideBar的效果呢。這需要用到組件中的通信,并且不是父子組件,
參考方法 1可以使用this.$root.$emitthis.$root.$on試試,event bus 2vuex,因?yàn)轫?xiàng)目里使用了vuex,所以應(yīng)該是從vuex找方法了
7路由懶加載和權(quán)限驗(yàn)證和進(jìn)度條和中英文切換
8require.context
9promise
10easy-mock.js
11支持無(wú)限嵌套路由,所有側(cè)邊欄這塊使用了遞歸組件
12api模塊和views組件命名一一對(duì)應(yīng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容